加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

Java 类型信息

发布时间:2020-12-14 06:32:43 所属栏目:Java 来源:网络整理
导读:《Thinking in Java 4th》第14章 类型信息 运行时类型信息(Run-Time Type Identification)使得你可以在程序运行时发现和使用类型信息。 14.1 为什么需要RTTI Circle,Square,Triangle三个类都继承自抽象类Shape,现有一个List 的数组,存的是Circle,Triangl

《Thinking in Java 4th》第14章 类型信息

运行时类型信息(Run-Time Type Identification)使得你可以在程序运行时发现和使用类型信息。

14.1 为什么需要RTTI

Circle,Square,Triangle三个类都继承自抽象类Shape,现有一个List的数组,存的是Circle,Triangle的对象,当你拿出一个对象时,你只知道它是Shape类,但不知道它的具体类型。使用RTTI,可以查询某个Space引用所指向的对象的具体类型。

14.2 Class对象

Java使用Class对象来执行其RTTI,它包含了与类有关的信息。每一个类都有一个Class对象,被保存在同名的.class文件中。为了生成这个类的对象,运行这个程序的JVM将使用被称为“类加载器”的子系统。

所有的类都是在对其第一次使用时,动态加载到JVM中的。当程序创建第一个对类的静态成员的引用时,就会加载这个类。因此,Java程序在它开始运行之前并未被完全加载。其各部分是在必需时才加载的。

类加载器首先检查这个类的Class对象时候已经加载,如果尚未加载,默认的类加载器就会根据类名查找.class文件。一旦某个类的Class对象被载入内存,它就被用来创建这个类的所有对象。

<span style="color: #0000ff;">class Candy { <span style="color: #0000ff;">static { System.out.println("Loading Candy"<span style="color: #000000;">); } }

<span style="color: #0000ff;">class Gum { <span style="color: #0000ff;">static { System.out.println("Loading Gum"<span style="color: #000000;">); } }

<span style="color: #0000ff;">class Cookie { <span style="color: #0000ff;">static { System.out.println("Loading Cookie"<span style="color: #000000;">); } }

<span style="color: #0000ff;">public <span style="color: #0000ff;">class<span style="color: #000000;"> SweetShop {
<span style="color: #0000ff;">public <span style="color: #0000ff;">static <span style="color: #0000ff;">void<span style="color: #000000;"> main(String[] args) {
System.out.println("inside main"<span style="color: #000000;">);
<span style="color: #0000ff;">new<span style="color: #000000;"> Candy();
System.out.println("After create Candy"<span style="color: #000000;">);
<span style="color: #0000ff;">try<span style="color: #000000;"> {
Class.forName("typeinfo.Gum");<span style="color: #008000;">//<span style="color: #008000;">书上没有加包名,亲测需要加
} <span style="color: #0000ff;">catch<span style="color: #000000;"> (ClassNotFoundException e) {
System.out.println("Couldn't find Gum"<span style="color: #000000;">);
}
System.out.println("After Class.forName("Gum")"<span style="color: #000000;">);
<span style="color: #0000ff;">new<span style="color: #000000;"> Cookie();
System.out.println("After create Cookie"<span style="color: #000000;">);
}
}

forName()是取得Class对象引用的一种方法,包含目标类的文本名的String作为输入,返回Class对象的引用。

<span style="color: #0000ff;">interface<span style="color: #000000;"> HasBatteries {}
<span style="color: #0000ff;">interface<span style="color: #000000;"> Waterproof {}
<span style="color: #0000ff;">interface<span style="color: #000000;"> Shoots {}

<span style="color: #0000ff;">class<span style="color: #000000;"> Toy {
Toy() {}
Toy(<span style="color: #0000ff;">int<span style="color: #000000;"> i) {}
}

<span style="color: #0000ff;">class FancyToy <span style="color: #0000ff;">extends Toy <span style="color: #0000ff;">implements<span style="color: #000000;"> HasBatteries,Waterproof,Shoots {
FancyToy() { <span style="color: #0000ff;">super(1<span style="color: #000000;">); }
}

<span style="color: #0000ff;">public <span style="color: #0000ff;">class<span style="color: #000000;"> ToyTest {
<span style="color: #0000ff;">static <span style="color: #0000ff;">void<span style="color: #000000;"> printInfo(Class cc) {
System.out.println("Class name: " + cc.getName() + " is interface? [" + cc.isInterface() + "]"<span style="color: #000000;">);
System.out.println("Simple name: " +<span style="color: #000000;"> cc.getSimpleName());
System.out.println("Canonical name: " + cc.getCanonicalName());<span style="color: #008000;">//<span style="color: #008000;">Canonical:规范化=_=
<span style="color: #000000;"> }
<span style="color: #0000ff;">public <span style="color: #0000ff;">static <span style="color: #0000ff;">void<span style="color: #000000;"> main(String[] args) {
Class c = <span style="color: #0000ff;">null<span style="color: #000000;">;
<span style="color: #0000ff;">try<span style="color: #000000;"> {
c = Class.forName("typeinfo.toys.FancyToy"<span style="color: #000000;">);
} <span style="color: #0000ff;">catch<span style="color: #000000;"> (ClassNotFoundException e) {
System.out.println("Can't find FancyToy"<span style="color: #000000;">);
System.exit(1<span style="color: #000000;">);
}
printInfo(c);
<span style="color: #0000ff;">for<span style="color: #000000;"> (Class face: c.getInterfaces()) {
printInfo(face);
}
Class up =<span style="color: #000000;"> c.getSuperclass();
Object obj = <span style="color: #0000ff;">null<span style="color: #000000;">;
<span style="color: #0000ff;">try<span style="color: #000000;"> {
<span style="color: #008000;">//<span style="color: #008000;"> 需要默认构造函数 即无参的构造函数 否则会报错
obj =<span style="color: #000000;"> up.newInstance();
} <span style="color: #0000ff;">catch<span style="color: #000000;"> (InstantiationException e) {
System.out.println("Cannot instantiate"<span style="color: #000000;">);
System.exit(1<span style="color: #000000;">);
} <span style="color: #0000ff;">catch<span style="color: #000000;"> (IllegalAccessException e) {
System.out.println("Cannot access"<span style="color: #000000;">);
System.exit(1<span style="color: #000000;">);
}
printInfo(obj.getClass());
}
}

通过对象.getClass()可以直接得到Class引用。

<span style="color: #0000ff;">public <span style="color: #0000ff;">class<span style="color: #000000;"> Exercise10 {
<span style="color: #0000ff;">public <span style="color: #0000ff;">static <span style="color: #0000ff;">void<span style="color: #000000;"> main(String[] args) {
<span style="color: #0000ff;">char[] ch = <span style="color: #0000ff;">new <span style="color: #0000ff;">char[10<span style="color: #000000;">];
Class cc =<span style="color: #000000;"> ch.getClass();
typeinfo.toys.ToyTest.printInfo(cc);
System.out.println(ch <span style="color: #0000ff;">instanceof<span style="color: #000000;"> Object);
}
}
<span style="color: #008000;">/*<span style="color: #008000;">
Class name: [C is interface? [false]
Simple name: char[]
Canonical name: char[]
true
<span style="color: #008000;">
/

14.2.1 类字面常量

通过类名.class也可以得到Class对象的引用。当使用".class"来创建对Class对象的引用时,不会自动地初始化该Class对象。

基本类型.class = 基本类型的包装类.class

<span style="color: #0000ff;">import java.util.*<span style="color: #000000;">;

<span style="color: #0000ff;">class<span style="color: #000000;"> Initable {
<span style="color: #0000ff;">static <span style="color: #0000ff;">final <span style="color: #0000ff;">int staticFinal = 47<span style="color: #000000;">;
<span style="color: #0000ff;">static <span style="color: #0000ff;">final <span style="color: #0000ff;">int staticFinal2 = ClassInitialization.rand.nextInt(1000<span style="color: #000000;">);
<span style="color: #0000ff;">static { System.out.println("Initializing Initable"<span style="color: #000000;">); }
}

<span style="color: #0000ff;">class<span style="color: #000000;"> Initable2 {
<span style="color: #0000ff;">static <span style="color: #0000ff;">int staticNotFinal = 147<span style="color: #000000;">;
<span style="color: #0000ff;">static { System.out.println("Initializing Initable2"<span style="color: #000000;">); }
}

<span style="color: #0000ff;">class<span style="color: #000000;"> Initable3 {
<span style="color: #0000ff;">static <span style="color: #0000ff;">int staticNotFinal = 74<span style="color: #000000;">;
<span style="color: #0000ff;">static { System.out.println("Initializing Initable3"<span style="color: #000000;">); }
}

<span style="color: #0000ff;">public <span style="color: #0000ff;">class<span style="color: #000000;"> ClassInitialization {
<span style="color: #0000ff;">public <span style="color: #0000ff;">static Random rand = <span style="color: #0000ff;">new Random(47<span style="color: #000000;">);
<span style="color: #0000ff;">public <span style="color: #0000ff;">static <span style="color: #0000ff;">void main(String[] args) <span style="color: #0000ff;">throws<span style="color: #000000;"> Exception {
Class initable = Initable.<span style="color: #0000ff;">class<span style="color: #000000;">;
System.out.println("After create Initable ref"<span style="color: #000000;">);
System.out.println(initable.isInterface());
System.out.println(Initable.staticFinal);
System.out.println(Initable.staticFinal2);
System.out.println(Initable2.staticNotFinal);
Class initable3 = Class.forName("typeinfo.Initable3"<span style="color: #000000;">);
System.out.println("After create Initable3 ref"<span style="color: #000000;">);
System.out.println(Initable3.staticNotFinal);
}

}

如果一个static final是“编译期常量”,那个这个值不需要对类初始化就可以读取。

14.2.2 泛化的Class引用

例:? intClass = .;?

使用Class优于Class。

向Class添加泛型是为了提供编译期类型检查。

感觉Java的泛型真神奇啊(= =)

Class 我也就忍了 竟然还有 Class up = TObj.getSuperclass();

Object obj = up.newInstance(); <-- 得到的只是Object

14.2.3 新的转型语法

按作者的意思,这个并没有什么用……

<span style="color: #0000ff;">class<span style="color: #000000;"> Building {}
<span style="color: #0000ff;">class House <span style="color: #0000ff;">extends<span style="color: #000000;"> Building {}

<span style="color: #0000ff;">public <span style="color: #0000ff;">class<span style="color: #000000;"> ClassCasts {
<span style="color: #0000ff;">public <span style="color: #0000ff;">static <span style="color: #0000ff;">void<span style="color: #000000;"> main(String[] args) {
Building b = <span style="color: #0000ff;">new<span style="color: #000000;"> House();
Class houseType = House.<span style="color: #0000ff;">class<span style="color: #000000;">;
House h =<span style="color: #000000;"> houseType.cast(b);
h = (House)b; <span style="color: #008000;">//<span style="color: #008000;"> ... or just do this.
<span style="color: #000000;"> }
}

14.3 类型转换前先做检查

如果你想向下转型,先用关键字instanceof检查

? (x ?

?//我发现作者有一种神奇的能力——把很简单的事情写成一大堆神烦的代码……就算写代码少写几行不行吗啊魂淡……一定是按字数付稿费……

?//我把那一堆代码抄完我都懒得复制过来了,头疼= =

使用 a instanceof AClass 就必须写AClass的类名。但是没有储存类名的容器呀,所以就想到改进方法,使用Class对象,然后使用它的Class对象.isInstanceof(目标对象)就可以辣!

isAssignableFrom ? 是用来判断一个类Class1和另一个类Class2是否相同或是另一个类的超类或接口。?

通常调用格式是 : ??

14.4 注册工厂

?没看懂(捂脸 先过……

14.5 instanceof 与 Class 的等价性

a instanceof B 等价于 B.class.isInstance(a) 当对象a的类型与B相同或者是其派生类时,返回true

a.getClass()==B.class 等价于 a.getClass.equals(B.class) 当且仅当对象a的类型与B相同时,返回true

14.6 反射:运行时的类信息

RTTI和反射之间真正的区别只在于,对RTTI来说,编译器在编译时打开检查.class文件。而对于反射机制来说,.class文件在编译时是不可获取的,所以是在运行时打开时和检查.class文件。

Class c = Class.forName(args[0== c.getConstructors();

args[0]在编译时是不可知的,但是通过反射,你可以知道类中的方法以及构造器。

事实上反射可以获得类的所以域和方法,甚至包括private。

设计模式什么的,真的看不懂啊~~~>_<~~~

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读