国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務(wù)器之家 - 編程語言 - JAVA教程 - 舉例講解Java的RTTI運(yùn)行時(shí)類型識(shí)別機(jī)制

舉例講解Java的RTTI運(yùn)行時(shí)類型識(shí)別機(jī)制

2020-04-26 11:25arthinking JAVA教程

這篇文章主要介紹了Java的RTTI運(yùn)行時(shí)類型識(shí)別機(jī)制,包括泛化的Class引用以及類型檢查instanceof等知識(shí)點(diǎn),需要的朋友可以參考下

1、RTTI:
運(yùn)行時(shí)類型信息可以讓你在程序運(yùn)行時(shí)發(fā)現(xiàn)和使用類型信息。

在Java中運(yùn)行時(shí)識(shí)別對(duì)象和類的信息有兩種方式:傳統(tǒng)的RTTI,以及反射。下面就來說下RTTI。

RTTI:在運(yùn)行時(shí),識(shí)別一個(gè)對(duì)象的類型。但是這個(gè)類型在編譯時(shí)必須已知。

下面通過一個(gè)例子來看下RTTI的使用。這里涉及到了多態(tài)的概念:讓代碼只操作基類的引用,而實(shí)際上調(diào)用具體的子類的方法,通常會(huì)創(chuàng)建一個(gè)具體的對(duì)象(Circle,Square,或者Triangle,見下例),把它向上轉(zhuǎn)型為Shape(忽略了對(duì)象的具體類型),并在后面的程序中使用匿名(即不知道具體類型)的Shape引用:

舉例講解Java的RTTI運(yùn)行時(shí)類型識(shí)別機(jī)制

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
abstract class Shape {
  // this 調(diào)用當(dāng)前類的toString()方法,返回實(shí)際的內(nèi)容
  void draw(){ System.out.println(this + "draw()"); }
  // 聲明 toString()為abstract類型,強(qiáng)制集成在重寫該方法
  abstract public String toString();
}
 
class Circle extends Shape {
  public String toString(){ return "Circle"; }
}
 
class Square extends Shape {
  public String toString(){ return "Square"; }
}
 
class Triangle extends Shape {
  public String toString(){ return "Triangle"; }
}
 
public static void main(String[] args){
  // 把Shape對(duì)象放入List<Shape>的數(shù)組的時(shí)候會(huì)向上轉(zhuǎn)型為Shape,從而丟失了具體的類型信息
  List<Shape> shapeList = Arrays.asList(new Circle(), new Square(), new Triangle());
  // 從數(shù)組中取出時(shí),這種容器,實(shí)際上所有的元素都當(dāng)成Object持有,會(huì)自動(dòng)將結(jié)果轉(zhuǎn)型為Shape,這就是RTTI的基本的使用。
  for(Shape shape : shapeList){
    shape.draw();
  }
}

輸出結(jié)果為:

?
1
2
3
Circledraw()
Squaredraw()
Triangledraw()

存入數(shù)組的時(shí)候,會(huì)自動(dòng)向上轉(zhuǎn)型為Shape,丟失了具體的類型,當(dāng)從數(shù)組中取出的時(shí)候,(List容器將所有的事物都當(dāng)做Object持有),會(huì)自動(dòng)將結(jié)果轉(zhuǎn)型回Shape,這就是RTTI的基本用法。Java中所有的類型轉(zhuǎn)換都是在運(yùn)行時(shí)進(jìn)行正確性檢查的,也就是RTTI:在運(yùn)行時(shí),識(shí)別一個(gè)對(duì)象的類型。

上面的轉(zhuǎn)型并不徹底,數(shù)組的元素取出時(shí)又Object轉(zhuǎn)型為Shape,而不是具體的類型,編譯時(shí)這是由容器和Java泛型系統(tǒng)來確保這一點(diǎn)的,而在運(yùn)行時(shí)時(shí)有類型轉(zhuǎn)換操作來確保這一點(diǎn)的。

而能夠通過Shape對(duì)象執(zhí)行到子類的具體代碼就是又多態(tài)來決定的了,具體看Shape引用所指向的具體對(duì)象。

另外,使用RTTI,可以查詢某個(gè)Shape引用所指向的對(duì)象的確切類型,然后選擇性的執(zhí)行子類的方法。

2、Class對(duì)象:
要了解RTTI在Java中的工作原理,必須知道類型信息在運(yùn)行時(shí)是如何表示的,這里是由Class這個(gè)特殊對(duì)象完成的。

Class對(duì)象是用來創(chuàng)建類的所有的“常規(guī)”對(duì)象的。Java使用Class對(duì)象來執(zhí)行其RTTI。

每當(dāng)編譯一個(gè)新類,就會(huì)產(chǎn)生一個(gè)Class對(duì)象(.class文件)。運(yùn)行這個(gè)程序的JVM將使用“類加載器”這個(gè)子系統(tǒng)。

類加載器子系統(tǒng):包含一條類加載器鏈,但只有一個(gè)原生類加載器,它是JVM實(shí)現(xiàn)的一部分。原生類加載器加載可信類,包括Java API類,通常是從本地磁盤加載的。當(dāng)需要以某種特定的方式加載類,以支持Web服務(wù)器應(yīng)用,可以掛接額外的類加載器。

2.1、加載類的時(shí)機(jī):
當(dāng)程序創(chuàng)建第一個(gè)對(duì)類的靜態(tài)成員的引用時(shí),就會(huì)加載這個(gè)類。這證明其實(shí)構(gòu)造器也是類的靜態(tài)方法,當(dāng)使用new操作符創(chuàng)建類的新對(duì)象也會(huì)當(dāng)做對(duì)類的靜態(tài)成員的引用。

可見Java程序時(shí)動(dòng)態(tài)加載的,按需加載。需要用到Class時(shí),類加載器首先會(huì)檢查這個(gè)類的Class對(duì)象是否已經(jīng)加載,如果尚未加載,默認(rèn)的類加載器就會(huì)根據(jù)類名查找到.class文件。接下來是驗(yàn)證階段:加載時(shí),它們會(huì)接受驗(yàn)證,以確保其沒有被破壞,并且不包含不良Java代碼。

2.2、Class相關(guān)方法,newInstance()
下面通過一個(gè)例子演示Class對(duì)象的加載:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class A {
  // 靜態(tài)代碼庫(kù),在第一次被加載時(shí)執(zhí)行,通過打印信息知道該類什么時(shí)候被加載
  static { System.out.println("Loading A"); }
}
class B {
  static { System.out.println("Loading B"); }
}
class C {
  static { System.out.println("Loading C"); }
}
public class Load {
  public static void main(String[] args){
    System.out.println("execute main...");
    new A();
    System.out.println("after new A");
    try {
      Class.forName("com.itzhai.test.type.B");
    } catch (ClassNotFoundException e) {
      System.out.println("cloud not find class B");
    }
    System.out.println("after Class.forName B");
    new C();
    System.out.println("after new C");
  }
}

輸出結(jié)果為:

?
1
2
3
4
5
6
7
execute main...
Loading A
after new A
Loading B
after Class.forName B
Loading C
after new C

可見,Class對(duì)象在需要的時(shí)候才被加載,注意到這里的Class.forName()方法:

forName()方法是取得Class對(duì)象的引用的一種方法,通過這個(gè)方法獲得恰當(dāng)?shù)腃lass對(duì)象的引用,就可以在運(yùn)行時(shí)使用類型信息了。

如果你已經(jīng)有了一個(gè)感興趣的類型的對(duì)象,則可以通過跟類Object提供的getClass()方法來獲得Class引用。

下面是一段Class的使用的代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
interface X{}
interface Y{}
interface Z{}
class Letter {
  Letter(){};
  Letter(int i){};
}
class NewLetter extends Letter implements X, Y, Z{
  NewLetter(){ super(1); };
}
public class ClassTest {
 
  /**
   * 打印類型信息
   * @param c
   */
  static void printInfo(Class c){
    // getName()獲得全限定的類名
    System.out.println("Class name: " + c.getName() + " is interface? " + c.isInterface());
    // 獲得不包含包名的類名
    System.out.println("Simple name: " + c.getSimpleName());
    // 獲得全限定類名
    System.out.println("Canonical name: " + c.getCanonicalName());
  }
 
  public static void main(String[] args){
    Class c = null;
    try {
      // 獲得Class引用
      c = Class.forName("com.itzhai.test.type.NewLetter");
    } catch (ClassNotFoundException e) {
      System.out.println("Can not find com.itzhai.test.type.NewLetter");
      System.exit(1);
    }
    // 打印接口類型信息
    for(Class face : c.getInterfaces()){
      printInfo(face);
    }
    // 獲取超類Class引用
    Class up = c.getSuperclass();
    Object obj = null;
    try {
      // 通過newInstance()方法創(chuàng)建Class的實(shí)例
      obj = up.newInstance();
    } catch (InstantiationException e) {
      System.out.println("Can not instantiate");
    } catch (IllegalAccessException e) {
      System.out.println("Can not access");
    }
    // 打印超類類型信息
    printInfo(obj.getClass());
  }
}

輸出為:

?
1
2
3
4
5
6
7
8
9
10
11
12
Class name: com.itzhai.test.type.X is interface? true
Simple name: X
Canonical name: com.itzhai.test.type.X
Class name: com.itzhai.test.type.Y is interface? true
Simple name: Y
Canonical name: com.itzhai.test.type.Y
Class name: com.itzhai.test.type.Z is interface? true
Simple name: Z
Canonical name: com.itzhai.test.type.Z
Class name: com.itzhai.test.type.Letter is interface? false
Simple name: Letter
Canonical name: com.itzhai.test.type.Letter

注意,在傳遞給forName()的字符串必須使用全限定名(包括包名)。

通過printInfo里面使用到的方法,你可以在運(yùn)行時(shí)發(fā)現(xiàn)一個(gè)對(duì)象完整的類繼承結(jié)構(gòu)。

通過使用Class的newInstance()方法是實(shí)現(xiàn)“虛擬構(gòu)造器”的一種途徑,用來創(chuàng)建Class的實(shí)例,得到的是Object引用,但是引用時(shí)指向Letter對(duì)象。使用newInstance()來創(chuàng)建的類,必須帶有默認(rèn)的構(gòu)造器。(而通過反射API,可以用任意的構(gòu)造器來動(dòng)態(tài)的創(chuàng)建類的對(duì)象)。

2.3、類字面常量:
除了使用getName()方法,Java還提供了另一種方法來生成對(duì)Class對(duì)象的引用,即使用類字面常量:

?
1
NewLetter.class;

此方法簡(jiǎn)單安全,編譯時(shí)就受到檢查,更高效。不僅可用于普通類,也可以用于接口,數(shù)組以及基本數(shù)據(jù)類型。另外,對(duì)于基本數(shù)據(jù)類型的包裝器類,還有一個(gè)標(biāo)準(zhǔn)字段TYPE,TYPE字段是一個(gè)引用,執(zhí)行對(duì)應(yīng)的基本數(shù)據(jù)類型的Class對(duì)象。為了統(tǒng)一,建議都使用.class這種形式。

2.4、使用.class與使用getName()方法創(chuàng)建對(duì)象引用的區(qū)別:
使用.class創(chuàng)建時(shí),不會(huì)自動(dòng)的初始化Class對(duì)象。創(chuàng)建步驟如下:

(1)加載 由類加載器執(zhí)行:查找字節(jié)碼(通常是在classpath指定的路徑中查找,但并非必須的),然后從這些字節(jié)碼中創(chuàng)建一個(gè)Class對(duì)象。

(2)鏈接 將驗(yàn)證類中的字節(jié)碼,為靜態(tài)域分配存儲(chǔ)空間,如果需要,將會(huì)解析這個(gè)類創(chuàng)建的對(duì)其他類的所有的引用。

(3)初始化 如果該類具有超類,則對(duì)其初始化,執(zhí)行靜態(tài)初始化器和靜態(tài)初始化塊。

初始化被延遲到了對(duì)靜態(tài)方法(構(gòu)造器隱式的是靜態(tài)的)或者非常數(shù)靜態(tài)域進(jìn)行首次引用時(shí)才執(zhí)行的:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class Data1{
  static final int a = 1;
  static final double b = Math.random();
  static {
    System.out.println("init Data1...");
  }
}
 
class Data2{
  static int a = 12;
  static {
    System.out.println("init Data2...");
  }
}
 
class Data3{
  static int a = 23;
  static {
    System.out.println("init Data3...");
  }
}
 
public class ClassTest2 {
  public static void main(String[] args){
    System.out.println("Data1.class: ");
    Class data1 = Data1.class;
    System.out.println(Data1.a); // 沒有初始化Data1
    System.out.println(Data1.b); // 初始化了Data1
    System.out.println(Data2.a); // 初始化了Data2
    try {
      Class data3 = Class.forName("com.itzhai.test.type.Data3"); // 初始化了Data3
    } catch (ClassNotFoundException e) {
      System.out.println("can not found com.itzhai.test.type.Data3...");
    }
    System.out.println(Data3.a);
  }
}

輸出的結(jié)果為:

?
1
2
3
4
5
6
7
8
Data1.class:
1
init Data1...
0.26771085109184534
init Data2...
12
init Data3...
23

初始化有效的實(shí)現(xiàn)了盡可能的“惰性”。

2.5、下面是判斷是否執(zhí)行初始化的一些情況:
(1)class語法獲得對(duì)類的引用不會(huì)引發(fā)初始化;

(2)Class.forName()產(chǎn)生了Class引用,立即進(jìn)行了初始化;

(3)如果一個(gè)static final值是“編譯器常量”,那么這個(gè)值不需要對(duì)類進(jìn)行初始化就可以被讀取;

(4)如果只是把一個(gè)域設(shè)置為static final還不足以確保這種行為,例如上面的:

?
1
static final double b = Math.random();

(5)如果一個(gè)static域bushifinal的,那么在對(duì)它訪問時(shí),總是要先進(jìn)性鏈接和初始化;

2.6、泛化的Class引用:
Class引用表示的是它所指向的對(duì)象的確切類型,而該對(duì)象便是Class類的一個(gè)對(duì)象。在JavaSE5中,可以通過泛型對(duì)Class引用所指向的Class對(duì)象進(jìn)行限定,并且可以讓編譯器強(qiáng)制執(zhí)行額外的類型檢查:

?
1
2
3
4
5
6
7
Class intCls = int.class;
// 使用泛型限定Class指向的引用
Class<Integer> genIntCls = int.class;
// 沒有使用泛型的Clas可以重新賦值為指向任何其他的Class對(duì)象
intCls = double.class;
// 下面的編譯會(huì)出錯(cuò)
// genIntCls = double.class;

2.6.1、使用通配符?放松泛型的限定:

?
1
2
Class<?> intCls = int.class;
intCls = String.class;

在JavaSE5中,Class<?>優(yōu)于平凡的Class,更建議使用Class<?>,即便它們是等價(jià)的,因?yàn)镃lass<?>的好處是它表示你并非是碰巧或者疏忽,而是使用了一個(gè)非具體的類引用。

為了限定Class的引用為某種類型,或者該類型的子類型可以將通配符與extends一起使用,創(chuàng)建一個(gè)范圍:

?
1
2
3
4
Class<? extends Number> num = int.class;
// num的引用范圍為Number及其子類,所以可以按照如下賦值
num = double.class;
num = Number.class;

2.6.2、泛型下的newInstance()方法:
使用了泛型后的Class,調(diào)用newInstance()返回的對(duì)象是確切類型的,但是當(dāng)你使用getSuperclass()獲取泛型對(duì)應(yīng)的超類的時(shí)候真正的類型會(huì)有一些限制:編譯器在編譯期就知道了超類的類型,但是,通過這個(gè)獲取到的超類引用的newInstance()方法返回的不是精確類型,而是Object:

?
1
2
3
4
5
6
7
8
9
10
11
Dog dog = dogCls.newInstance();
abstract class Animal {
}
class Dog extends Animal{
}
 
// 下面的寫法是錯(cuò)誤的,只能返回 Class<? super Dog>類型
// Class<Animal> animalCls = dogCls.getSuperclass();
Class<? super Dog> animalCls = dogCls.getSuperclass();
// 通過獲取的超類引用,只能創(chuàng)建返回Object類型的對(duì)象
Object obj = animalCls.newInstance();

2.6.3、新的轉(zhuǎn)型語法:cast()方法
直接看下代碼:

?
1
2
3
4
5
Animal animal = new Dog();
Class<Dog> dogCls = Dog.class;
Dog dog = dogCls.cast(animal);
// 或者直接使用下面的轉(zhuǎn)型方法
dog = (Dog)animal;

可以發(fā)現(xiàn),使用cast()方法的做了額外的工作,這種轉(zhuǎn)換方法可以用在一下的情況中:在編寫泛型帶的時(shí)候,如果存儲(chǔ)了Class引用,并希望通過這個(gè)Class引用來執(zhí)行轉(zhuǎn)型,就可以使用cast()方法。

3、類型檢查 instanceof
3.1、類型轉(zhuǎn)換前先做檢查

編譯器允許你自由的做向上轉(zhuǎn)型的賦值操作,而不需要任何顯示的轉(zhuǎn)型操作,就好像給超類的引用賦值那樣。

然而如果不使用顯示的類型轉(zhuǎn)換,編譯器就不允許你執(zhí)行向下轉(zhuǎn)換賦值,這個(gè)時(shí)候我們不妨先來檢查一下對(duì)象是不是某個(gè)特定類型的實(shí)例,使用到了關(guān)鍵字 instanceof:

?
1
2
if(x instanceof Dog)
  ((Dog) x).bark();

3.2、RTTI的形式:
所以,到目前為止,我們知道RTTI的形式包括:

(1)傳統(tǒng)的類型轉(zhuǎn)換 (Shape)

(2)代表對(duì)象的類型的Class對(duì)象

(3)關(guān)鍵字instanceof

3.3、動(dòng)態(tài)的instanceof方法:
Class.isInstance方法提供給了一種動(dòng)態(tài)測(cè)試對(duì)象的途徑。

下面演示下instanceof和Class.isInstance的用法:

Attribute:

?
1
2
3
public interface Attribute {
 
}

Shape:

?
1
2
3
4
5
6
7
8
9
/**
 * 創(chuàng)建一個(gè)抽象類
 */
public abstract class Shape{
  // this調(diào)用了當(dāng)前類的toString方法獲得信息
  public void draw() { System.out.println(this + ".draw()"); }
  // 聲明toString()方法為abstract,從而強(qiáng)制繼承者需要重寫該方法。
  abstract public String toString();
}

Circle:

?
1
2
3
public class Circle extends Shape implements Attribute{
  public String toString(){ return "Circle"; }
}

Square:

?
1
2
3
public class Square extends Shape{
  public String toString(){ return "Square"; }
}

Triangle:

?
1
2
3
public class Triangle extends Shape{
  public String toString(){ return "Triangle"; }
}

類型檢查:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// instanceOf
Circle c = new Circle();
// 判斷是否超類的實(shí)例
System.out.format("Using instanceof: %s is a shape? %b ",
    c.toString(), c instanceof Shape);
// 判斷是否Circle的實(shí)例
System.out.format("Using instanceof: %s is a circle? %b ",
    c.toString(), c instanceof Circle);
// 判斷是否超類的實(shí)例
System.out.format("Using Class.isInstance: %s is a shape? %b ",
    c.toString(), Shape.class.isInstance(c));
// 判斷是否接口的實(shí)例
System.out.format("Using Class.isInstance: %s is a Attribute? %b ",
    c.toString(), Attribute.class.isInstance(c));

可以發(fā)現(xiàn),instanceof或者Class.isInstance方法判斷了是否繼承體系的實(shí)例,即除了判斷本身,還判斷是否超類或接口的實(shí)例。

下面演示下使用動(dòng)態(tài)的Class.instance的用法:

首先創(chuàng)建一個(gè)抽象的形狀生成器類:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public abstract class ShapeCreator {
  private Random rand = new Random(10);
  // 返回一個(gè)對(duì)象類型數(shù)組,由實(shí)現(xiàn)類提供,后面會(huì)看到兩種實(shí)現(xiàn)形式,基于forName的和基于類字面常量的.class
  public abstract List<Class<? extends Shape>> types();
  // 隨機(jī)生成一個(gè)對(duì)象類型數(shù)組中的類型對(duì)象實(shí)例
  public Shape randomShape(){
    int n = rand.nextInt(types().size());
    try {
      return types().get(n).newInstance();
    } catch (InstantiationException e) {
      e.printStackTrace();
      return null;
    } catch (IllegalAccessException e) {
      e.printStackTrace();
      return null;
    }
  }
  // 生成一個(gè)隨機(jī)數(shù)組
  public Shape[] createArray(int size){
    Shape[] result = new Shape[size];
    for(int i=0; i<size; i++){
      result[i] = randomShape();
    }
    return result;
  }
  // 生成一個(gè)隨機(jī)數(shù)組,泛型的ArrayList
  public ArrayList<Shape> arrayList(int size){
    ArrayList<Shape> result = new ArrayList<Shape>();
    Collections.addAll(result, createArray(size));
    return result;
  }
}

接下來編寫一個(gè)該抽象類的實(shí)現(xiàn):

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
 * forName的生成器實(shí)現(xiàn)
 * @author arthinking
 *
 */
public class ForNameCreator extends ShapeCreator{
 
  private static List<Class<? extends Shape>> types =
      new ArrayList<Class<? extends Shape>>();
  private static String[] typeNames = {
    "com.itzhai.javanote.entity.Circle",
    "com.itzhai.javanote.entity.Square",
    "com.itzhai.javanote.entity.Triangle"
  };
 
  @SuppressWarnings("unused")
  private static void loader(){
    for(String name : typeNames){
      try {
        types.add((Class<? extends Shape>)Class.forName(name));
      } catch (ClassNotFoundException e) {
        e.printStackTrace();
      }
    }
  }
  // 初始化加載所需的類型數(shù)組
  static {
    loader();
  }
  public List<Class<? extends Shape>> types() {
    return types;
  }
}

最后寫一個(gè)統(tǒng)計(jì)形狀個(gè)數(shù)的類,里面用到了instanceof:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class ShapeCount {
 
  static class ShapeCounter extends HashMap<String, Integer>{
    public void count(String type){
      Integer quantity = get(type);
      if(quantity == null){
        put(type, 1);
      } else {
        put(type, quantity + 1);
      }
    }
  }
 
  // 演示通過instanceof關(guān)鍵字統(tǒng)計(jì)對(duì)象類型
  public static void countShapes(ShapeCreator creator){
    ShapeCounter counter = new ShapeCounter();
    for(Shape shape : creator.createArray(20)){
      if(shape instanceof Circle)
        counter.count("Circle");
      if(shape instanceof Square)
        counter.count("Square");
      if(shape instanceof Triangle){
        counter.count("Triangle");
      }
    }
    System.out.println(counter);
  }
 
  public static void main(String[] args){
    countShapes(new ForNameCreator());
  }
}

改寫一下抽象類的實(shí)現(xiàn),重新用類字面常量實(shí)現(xiàn):

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
 * 字面量的生成器實(shí)現(xiàn)
 */
public class LiteralCreator extends ShapeCreator{
 
  public static final List<Class<? extends Shape>> allType =
      Collections.unmodifiableList(Arrays.asList(Circle.class, Triangle.class, Square.class));
 
  public List<Class<? extends Shape>> types(){
    return allType;
  }
 
  public static void main(String[] args){
    System.out.println(allType);
  }
 
}

現(xiàn)在使用Class.instance統(tǒng)計(jì)形狀的個(gè)數(shù)如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
 * 通過使用Class.instanceof動(dòng)態(tài)的測(cè)試對(duì)象,移除掉原來的ShapeCount中單調(diào)的instanceof語句
 *
 */
public class ShapeCount2 {
 
  private static final List<Class<? extends Shape>> shapeTypes = LiteralCreator.allType;
 
  static class ShapeCounter extends HashMap<String, Integer>{
    public void count(String type){
      Integer quantity = get(type);
      if(quantity == null){
        put(type, 1);
      } else {
        put(type, quantity + 1);
      }
    }
  }
 
  // 演示通過Class.isInstance()統(tǒng)計(jì)對(duì)象類型
  public static void countShapes(ShapeCreator creator){
    ShapeCounter counter = new ShapeCounter();
    for(Shape shape : creator.createArray(20)){
      for(Class<? extends Shape> cls : shapeTypes){
        if(cls.isInstance(shape)){
          counter.count(cls.getSimpleName());
        }
      }
    }
    System.out.println(counter);
  }
 
  public static void main(String[] args){
    countShapes(new ForNameCreator());
  }
}

現(xiàn)在生成器有了兩種實(shí)現(xiàn),我們?cè)谶@里可以添加一層外觀,設(shè)置默認(rèn)的實(shí)現(xiàn)方式:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
 * 現(xiàn)在生成器有了兩種實(shí)現(xiàn),我們?cè)谶@里添加一層外觀,設(shè)置默認(rèn)的實(shí)現(xiàn)方式
 */
public class Shapes {
 
  public static final ShapeCreator creator =
      new LiteralCreator();
  public static Shape randomShape(){
    return creator.randomShape();
  }
  public static Shape[] createArray(int size){
    return creator.createArray(size);
  }
  public static ArrayList<Shape> arrayList(int size){
    return creator.arrayList(size);
  }
}

3.4、instanceof與Class的等價(jià)性:
instanceof和isInstance()生成的結(jié)果完全一樣,保持了類型的概念,判斷是否一個(gè)類或者是這個(gè)類的派生類。

equals()與==也是一樣的,而使用這個(gè)比較實(shí)際的Class對(duì)象,就沒有考慮繼承。

?
1
2
3
4
System.out.println(new Circle() instanceof Circle); // true
System.out.println(Shape.class.isInstance(new Circle())); // true
System.out.println((new Circle()).getClass() == Circle.class); // true
System.out.println((new Circle().getClass()).equals(Shape.class)); // false

 

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 免费黄色在线 | 亚洲在线视频 | 91精品国产综合久久久久 | 韩日欧美 | 国产成人一区二区 | 欧美狠狠操 | 黄色av免费在线播放 | 午夜免费av | 99久久婷婷国产综合精品草原 | 日本视频免费观看 | 99精品一区 | 日韩在线不卡一区 | 成人高清网站 | 欧美一区二区在线视频 | 在线观看av片 | 999这里只有是极品 最新中文字幕在线 | 久久精品国产99国产精2020新增功能 | 成人免费视频亚洲 | 中文字幕1区 | 久久综合久久综合久久综合 | 涩涩涩久久久成人精品 | 91精品国产91久久综合 | 成人免费观看高清视频 | 激情久久婷婷 | 黄色在线观看视频网站 | 欧美日韩一区二区三区在线观看 | 色呦呦网站在线观看 | 成人在线免费观看视频 | 国产精品欧美一区二区三区 | 99久久精品国产毛片 | 午夜免费视频 | 成人h视频 | 日韩成人在线一区 | 国内精品一区二区三区 | 国产午夜视频 | 欧美成人一区二区 | 日韩成人在线免费观看 | 久久亚洲国产精品 | www.午夜 | 国偷自产一区二区免费视频 | 97伦理在线|