JAVA笔记四:接口、lambda表达式与内部类

一、接口

1.1接口的概念

接口不是类,而是对类的一组需求描述 ,接口所有方法自动为public,当然在定义接口的时候加上也不违反语法规则。

java.lang.Comparable<T>1.0
int compareTo(T other) //小于other则返回负值,相等返回0,大于返回正值。

java.util.Arrays 1.2
static void sort(Object[] a)//数组中的元素必须属于实现了Comparable接口的类。

java.lang.Integer 1.0
static int compare(int x, int y)7

java.lang.Double 1.0
static int compare(double x, double y) 1.4

1.2 接口的特性

  1. 接口不是类,不能new一个接口实例对象,但是与抽象类相似,可以声明接口的对象变量来绑定实现了该接口的类对象实例。
Comapreble x = new Employee(...);// 1
double SPEED_LIMIT = 95; // 2
default int compareTo(T other) {return 0;}
class Student implements Person, Named
{
	public String getName(){return Person.super.getName();} //4.2
}
  1. 接口不可以包含实例域或静态方法,但是可以包含常量。(将自动设为 public static final)
  2. java SE 8中允许在接口中增加静态方法。
  3. 可以定义默认方法 default
    默认方法冲突:超类定义方法与接口默认方法同名且参数类型相同;两个接口的默认方法同名且参数类型相同
    1)超类优先,超类定义的方法会忽略接口定义的默认方法
    2)接口冲突,两个接口中的同名方法一旦有一个定义为默认,则必须由程序员解决,例如在类中定义方法覆盖。
    注:不能让接口的默认方法定义Object类中的某个方法,为什么呢?

1.3 接口示例

  1. Comparator接口
按长度比较字符串
class LengthComparator implements Comparator<String>{
	public int compare(String first, String second){
		return first.length() - second.length();
	}
}
String [] friends = {"Perter", "Paul", "Mary"};
Arrays.sort(friends, new LengthComparator());//sort的第二个版本

二、Lambda表达式

2.1、语法

(1)Lambda无需指定返回类型
(String first, String second)
 -> first.length() - second.length()

(2) 放置在花括号里
(String first, String second) ->
{
	if(first.length() < second.length()) return -1;
	else if (first.length() > second.length()) return 1;
	else return 0;
}

(3)即使没有参数也需要有括号
() -> {for(int i = 100; i >= 0; i --) System.out.println(i);}

(4)如果可以推导出参数类型,则可以省略
Comparator<String> comp
= (first, second) -> first.length() - second.length();

(5)如果只有一个参数,而且这个参数可以被推导出,可以省略小括号
ActionListener listener = event ->
	System.out.println("The time is " + new Date()");

2.2、函数式接口

对于只有一个抽象方法的接口,需要这种接口的对象时,可以提供一个lambda表达式,这种接口称为函数式接口。lambda可以转换为函数式接口。

2.2.1 方法引用

  • object::instanceMethod
  • Class::staticMethod
  • Class::instanceMethod
(1)前两种情况等价于提供参数的lambda表达式
System.out::println 等价于 x->System.out.println(x)
Math::pow 等价于 (x, y) -> Math.pow(x, y)

(2)对于第三种情况,第一个参数会成为方法的目标:
String::compareToIgnoreCase 等价于 (x, y) -> x.compareToIgnoreCase(y)
(3)在类中还可以使用this,super
this::greet, super::greet

2.2.2 构造器引用

Person::new,调用哪个构造器取决于上下文
Java有一个限制,无法构造泛型类型T的数组。数组构造器引用对于克服这个限制很有用。

Object[] people = stream.toArray();
Person[] people = stream.toArray(Person[]::new);

2.2.3 变量作用域

lambda表达式可以捕获外部变量(但必须是最终变量:String,初始化后不会赋新值)
lambda不能有同名的局部变量

2.2.4 Comparator

Arrays.sort(people, Comparator.comparing(Person::getName).thenComparing(Person::getFirstName));

2.3、 内部类

只有内部类可以是私有的,而常规类只可以具有包可见性或公有可见性。
内部类可访问外部类的域,包括私有域。使用外围类可以直接用变量名,也可以用
OuterClass.this //(TalkingClock.this.beep)
在外部类中,可以这样调用构造器
this.new TimePrinter() // TimePrinter 是内部类,通常this是多余的
但是如果TimePrinter是公有的,则任何外部主类的实例都可以构造一个TimePrinter

TalkingClock jabberer = new TalkingClock(1000, true);
TalkingClock.TimePrinter listener = jabberer.new TimePrinter();

内部类种声明的所有静态域都必须是final:
因为我们希望静态域只有一个实例,不过对于每个外部对象,会分别有一个单独的内部类实例。如果这个域不是final,它可能就不是唯一的。
内部类不能有static方法。

2.3.1 局部内部类

在方法中可以定义局部内部类
局部内部类,类似于局部变量,只存在于作用域内。
访问外部方法的变量,实质上在内部类中声明为final类型,注意如果是类,final的意思是绑定不可变,但值可变。

2.3.2 匿名内部类

假如只创建这个类的一个对象,就不必命名了,这种类被称为匿名内部类。通常的语法格式

SuperType xxx = new SuperType(construction parameters)//SuperType可以是接口也可以是一个类
{
	inner class methods and data
}//匿名内部类与普通构造一个SuperType的区别在于,后面跟了花括号

2.3.3 静态内部类

有时候使用内部类知识为了把一个类隐藏在另外一个类的内部,并不需要内部类引用外围类对象,为此可以将内部类声明为static,以便去取消产生的引用。在引入多个排序接口时可以使用。

三、代理

p258 比较难,看的有点迷糊
1、何时使用代理
假设有一个表示接口的Class对象,它的确切类型在编译时无法知道。代理机制则是一种更好的解决方案。代理类可以在运行时创建全新的类。这样的代理类能实现指定的接口。

java.langreflect.InvocationHandler 1.3
Object invoke(Object proxy, Method method, Object[] args)

目前为止,Java程序设计语言的继承概念介绍完了。

猜你喜欢

转载自blog.csdn.net/hunt_ing/article/details/83820706