1. 程式人生 > >JAVA筆記四:介面、lambda表示式與內部類

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程式設計語言的繼承概念介紹完了。