1、Class对象

  Class对象是一个特殊的对象,它包含了与类有关的信息。Class对象就是用来创建类的所有常规对象的。

  类是程序的一部分,每个类都有一个Class对象,每当编写并且编译一个新类,就会产生一个Class对象。为了生成这个对象,运行这个程序的Java虚拟机(JVM)的使用被称为 类加载器 的子系统。

  所有的类都是在对其第一次使用时,动态加载到JVM中的,当程序创建第一个对类的静态的引用时,就会加载这个类。当我们使用new关键字创建一个类的第一个对象的时候,JVM会帮助我们加载该类Class对象

  类加载器首先检查这个类的CLASS对象是否被加载,如果尚未加载,默认的类加载器就会根据类名查找.class文件

  想自己加载这个类的Class对象有三个办法:

  a、Class.forName("类名字符串") (注意:类名字符串必须是全称,包名+类名)

  b、类字面常量法:类名.class

  c、实例对象.getClass()

    class Candy{
static {System.out.println("Candy");}
}
class Sun{
static {System.out.println("Sun");}
} public class PP {
public static void main(String[] args) {
new Candy();
try {
Class.forName("Sun");
}catch(ClassNotFoundException e) {
System.out.println("Candy can't find");
} try {
Class.forName("SS");
}catch(ClassNotFoundException e) {
System.out.println("Candy can't find");
}
}
}

输出:

Candy
Sun
Candy can't find

这里有两个类,两个类都有一个static语句,每当类在第一次加载的时候就会执行打印出类的名字。

Class.forName("Sun");这个.forName()方法是一个Class类的static成员,这是一种取得Class对象的引用的方法,这里的主要作用是加载Sun类,加载的过程中static子句将被执行。

如果Class.forName()找不到想要加载的类,它就会抛出ClassNotFoundException

    interface Ss{}
interface Ss2{} class Candy{
}
class Sun extends Candy implements Ss,Ss2 {
static {System.out.println("Sun");}
} public class PP {
static void pr(Class cc) {
System.out.println("cc.getname:" + cc.getName());
System.out.println("is interface?:" + cc.isInterface());
System.out.println("cc SimpleName:" + cc.getSimpleName());
System.out.println("cc CanonicalName:" + cc.getCanonicalName()); }
public static void main(String[] args) {
Class c = null; try {
c = Class.forName("Sun");
}catch(ClassNotFoundException e) {
System.out.println("Sun can't find");
} pr(c);
System.out.println(); for(Class face: c.getInterfaces()) {
pr(face);
}
System.out.println(); Class up = c.getSuperclass();
pr(up); }
}

这里有两个接口 Ss Ss2 和两个类Candy和Sun,其中Candy是Sun的子类并实现了Ss Ss2 两个接口。

输出:

Sun
cc.getname:Sun
is interface?:false
cc SimpleName:Sun
cc CanonicalName:Sun cc.getname:Ss
is interface?:true
cc SimpleName:Ss
cc CanonicalName:Ss
cc.getname:Ss2
is interface?:true
cc SimpleName:Ss2
cc CanonicalName:Ss2 cc.getname:Candy
is interface?:false
cc SimpleName:Candy
cc CanonicalName:Candy

pr()方法可传入一个Class对象作为参数,这个方法将调用Class的getName()产生全限定的类名(我这不知道为什么不是==),isInterface()判断是不是一个接口,getSimpleName()产生不含包名的类名,getCanonicalName()也是产生全限定的类名(我这也是不知道为什么不是==)

main方法中,.getInterfaces()获得该对像所包含的接口,.getSuperclass()可以获得基类。

import java.util.*;

class Initable {
static final int staticfinal = 41;
static final int staticfinal2 = PP.rand.nextInt(1000);
static {System.out.println("Initable");}
}
class Initable2 {
static int staticfinal = 141;
static {System.out.println("Initable2");}
}
class Initable3 {
static int staticfinal = 74;
static {System.out.println("Initable3");}
}
public class PP {
public static Random rand = new Random(47);
public static void main(String[] args) {
Class initable = Initable.class;
System.out.println(Initable.staticfinal);
System.out.println(Initable.staticfinal2);
System.out.println(Initable2.staticfinal);
try {
Class initable3 = Class.forName("Initable3");
} catch (ClassNotFoundException e) {
System.out.println("Initable3 can't find");
}
System.out.println(Initable3.staticfinal);
}
}

输出:

41
Initable
258
Initable2
141
Initable3
74

这里的输出证明:

  1、Class initable = Initable.class;这样获取一个Class对象,并不会引起初始化。

  2、static final的变量是编译器常量不需要初始化就能被读取。

  3、如果这是static final还不能保证2的结论,就像staticfinal2这个变量的值来自于PP类的rand对象的nextInt()方法,这样将会被强制进行初始化。

  4、Class.forName()会引起初始化。

2、泛化的Class引用

  Class的引用总是指向某个Class对象,它可以制造类的实例,并包含可作用于这些实例的所有方法代码。它还包含该类的静态成员,因此,Class引用表示的就是它所指向的对象的确切类型,而该对象便是Class类的一个对象。

public class Gener {
public static void main(String[] args) {
Class intClass = int.class;
Class<Integer> genIntClass = int.class;
genIntClass = Integer.class;
intClass = double.class;
//genIntClass = double.class; Type mismatch: cannot convert from Class<Double> to Class<Integer>
}
}

  这里创建了两个Class对象,普通的类引用并不会产生警告信息,泛型类引用只能赋值为其声明的类型,但是普通的类引用可以被重新赋值为指向任何其他的Class对象。

  为了使在使用泛化的Class引用放松限制,可以使用通配符,通配符“?”,表示任何事物。

public class Gener {
public static void main(String[] args) {
Class intClass = int.class;
Class<?> genIntClass = int.class;
genIntClass = Integer.class;
intClass = double.class;
genIntClass = double.class;
}
}

  这样就不会产生编译器警告信息。

  为了创建为某种类型,或是该类型的任意子类型,需要将通配符与extends关键字相结合,

public class Gener {
public static void main(String[] args) {
Class<? extends Number> genIntClass = int.class;
genIntClass = double.class;
genIntClass = Number.class;
}
}

  向Class引用添加泛型语法的原因仅仅是为了提供编译期的类型检查,因此如果你操作错误,稍后就会发现这一点,使用普通Class引用时,直到运行才会发现这个错误

class coun{
private static long counter;
private final long id = counter++;
public String toString() { return Long.toString(id);} }
class FilledList<T>{
private Class<T> type;
public FilledList(Class<T> type) {
this.type = type;
}
public List<T> create(int eElements){
List<T> result = new ArrayList<T>();
try {
for(int i = 0; i < eElements; i++ ) {
result.add(type.newInstance());
}
}catch(Exception e) {
throw new RuntimeException(e);
}
return result;
}
}
public class Gener { public static void main(String[] args) {
FilledList<coun> fl =
new FilledList<coun>(coun.class);
System.out.println(fl.create(15));
}
}

这里构建了一个FilledList类,拥有一个泛型的Class类字段,随后又产生了一个List,使用.newInstance()来填充这个List,.newInstance()方法是实现“虚拟构造器”的一种途径,虚拟构造器允许你声明:"我不知道你的确切类型,但是无论如何我都要创建你",这里在填充List的时候因为是使用的泛型,所以add()的时候并不知道添加的对象是什么类型的,所以这里使用Class的.newInstance()方法。

输出:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

注意:这个类必须假设与他一同工作的任何类型都具有一个默认的构造器(无参构造器),如果不符合这个条件,你将得到一个异常。因为.newInstance()是没有参数的,想要生成一个需要传入参数才能创建的对象必然是失败的。

class toy{

}
class fancy extends toy { }
public class Gener { public static void main(String[] args) throws Exception {
Class<fancy> ftclass = fancy.class;
fancy ft = ftclass.newInstance(); Class<? super fancy> up = ftclass.getSuperclass(); //Class<toy> up = ftclass.getSuperclass(); Object obj = up.newInstance();
}
}

  这里定义了这个类,toy是fancy的父类,如果你想要通过子类的Class对象创建一个其父类的Class对象,编译器将只允许你声明父类引用是“某个类,它是fancy的父类”,将像Class<? super fancy>这样的表达,Class<toy>这样的声明是不会被允许的。

  因为getSuperclass()方法返回的是基类(不是接口),并且编译器在编译器就知道它是什么类型了。

3、Class引用的转型语法

  

class toy{

}
class fancy extends toy { }
public class Gener { public static void main(String[] args) throws Exception {
toy t = new toy();
Class<fancy> fancyType = fancy.class;
fancy f = fancyType.cast(t);
}
}

  cast()方法接受参数对象,并将器转型为Clsss引用的类型。这里一开始创建了一个toy类型的对象t,然后创建了一个fancy的Class对象fancyType,然后调用fancyType这个Classd对象的cast()方法传入t,将这个t转型为fancyType这个Classd对象引用的类型fancy。

toy t = new toy();
fancy f = (fancy)t;  

  其实实现的功能和这两句一样,。只是cast这种转型语法用在对于无法使用普通转型的情况,在编写泛型代码的时候,如果存储了Class引用,并希望以后通过这个引用来执行转型。

4、类型转换前检查

  instanceof是在java中RTTI的一种形式的关键字,还有传统的“(fancy)”类型转换,然后就是代表对象的类型的Class对象。

  instanceof返回一个布尔值,告诉我们对象是不是某个特定类型的实例。

if((x instanceof Dog)
((Dog)x).bark();

  在将x转型成一个Dog之前,上面的if语句会先检查x对象是不是属于Dog类。

5、instanceof与Class的等价性

class base{}
class Derived extends base{} public class Gen { static void test(Object x) {
System.out.println("x getclass," + x.getClass());
System.out.println("x instanceof base," + (x instanceof base));
System.out.println("x instanceof Derived," + (x instanceof Derived));
System.out.println("base.isInstance(x)," + base.class.isInstance(x));
System.out.println("Derived.isInstance(x)," + Derived.class.isInstance(x));
System.out.println("x.getClass() == base.class," + (x.getClass() == base.class));
System.out.println("x.getClass() == Derived.class," + (x.getClass() == Derived.class));
System.out.println("x.getClass().equals(base.class)," + (x.getClass().equals(base.class)));
System.out.println("x.getClass().equals(Derived.class)," + (x.getClass().equals(Derived.class)));
}
public static void main(String[] args) {
test(new base());
test(new Derived());
} }

输出:

x getclass,class base
x instanceof base,true
x instanceof Derived,false
base.isInstance(x),true
Derived.isInstance(x),false
x.getClass() == base.class,true
x.getClass() == Derived.class,false
x.getClass().equals(base.class),true
x.getClass().equals(Derived.class),false
x getclass,class Derived
x instanceof base,true

从输出可以看出来,instanceof和isInstance()得到的结果是一样的,equals和==也是一样的,但是instanceof考虑的是“你是这个类,或者是这个类的派生类吗”,== 就没有考虑继承

Java——类型信息的更多相关文章

  1. JAVA类型信息——反射机制

    JAVA类型信息——反射机制 一.反射机制概述 1.反射机制:就是java语言在运行时拥有的一项自我观察的能力,java通过这种能力彻底了解程序自身的情况,并为下一步的动作做准备. 2.反射机制的功能 ...

  2. JAVA类型信息——Class对象

    JAVA类型信息——Class对象 一.RTTI概要 1.类型信息RTTI :即对象和类的信息,例如类的名字.继承的基类.实现的接口等. 2.类型信息的作用:程序员可以在程序运行时发现和使用类型信息. ...

  3. Java基础 -- 深入理解Java类型信息(Class对象)与反射机制

    一 RTTI概念 认识Claa对象之前,先来了解一个概念,RTTI(Run-Time Type Identification)运行时类型识别,对于这个词一直是 C++ 中的概念,至于Java中出现RT ...

  4. Java类型信息

    一.引言 最近在阅读<Java编程思想>,学习一下java类型信息,现在做一下总结.Java如何让我们在运行时识别对象和类的信息的.主要有两种方式:一种是传统的“RTTI”,它假定我们在编 ...

  5. JAVA类型信息——Class对象(转载)

    JAVA类型信息--Class对象 一.RTTI概要 1.类型信息RTTI :即对象和类的信息,例如类的名字.继承的基类.实现的接口等. 2.类型信息的作用:程序员可以在程序运行时发现和使用类型信息. ...

  6. Thinking in Java -- 类型信息RTTI

    Thinking in Java – 类型信息 个人感觉 java 中的比較难的部分了,在看了些netty源代码发现事实上这块很实用. 这章重点是RTTI和反射.先说下自己的理解 RTTI是执行时识别 ...

  7. Java类型信息(RTTI和反射)

    要想在IT领域站得住脚,必须得不断地学习来强化自己,但是学过的技术不实践很容易便被遗忘,所以一直都打算开个博客,来记录自己学的知识,另外也可以分享给有需要的人! 最近在学习反射,为了更好地理解反射,就 ...

  8. Java 类型信息

    <Thinking in Java 4th>第14章 类型信息 运行时类型信息(Run-Time Type Identification)使得你可以在程序运行时发现和使用类型信息. 14. ...

  9. Java 类型信息 —— 获取泛型类型的类对象(.class)

    How to get a class instance of generics type T 考虑泛型类Foo<T>,在其成员中,如果想获取类型(type)T的类实例(class inst ...

  10. Java 类型信息详解和反射机制

    本文部分摘自 On Java 8 RTTI RTTI(RunTime Type Information)运行时类型信息,能够在程序运行时发现和使用类型信息,把我们从只能在编译期知晓类型信息并操作的局限 ...

随机推荐

  1. 深入学习Spring框架(一)- 入门

    1.Spring是什么? Spring是一个JavaEE轻量级的一站式开发框架. JavaEE: 就是用于开发B/S的程序.(企业级) 轻量级:使用最少代码启动框架,然后根据你的需求选择,选择你喜欢的 ...

  2. .Net Core 防止跨站点请求伪造

    一.在From 表单中生成 antiforgery 令牌 1. ASP.NET Core MVC 和 Razor 页模板中的窗体的所有生成 antiforgery 令牌,唯一且不可预测.服务器先发送到 ...

  3. 如何在vue中监听scroll,从而实现滑动加载更多

    首先需要明确3个定义: 文档高度:整个页面的高度 可视窗口高度:你看到的浏览器可视屏幕高度 滚动条滚动高度: 滚动条下滑过的高度 当 文档高度 = 可视窗口高度 + 滚动条高度  时,滚动条正好到底. ...

  4. 快速掌握mongoDB(二)——聚合管道和MapReduce

    上一节简单介绍了一下mongoDB的增删改查操作,这一节将介绍其聚合操作.我们在使用mysql.sqlserver时经常会用到一些聚合函数,如sum/avg/max/min/count等,mongoD ...

  5. 牛客小白月赛16 E 小雨的矩阵 ( 暴搜)

    链接:https://ac.nowcoder.com/acm/contest/949/E来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言52428 ...

  6. 小白之入口即化——十分钟看懂while循环,字符串格式化,运算符

    while循环 while循环-死循环 while空格+条件+冒号 缩进+循环体 3.打断死循环 break--终止当前循环 while True: print(123) print(234) bre ...

  7. 个人永久性免费-Excel催化剂功能第88波-批量提取pdf文件信息(图片、表格、文本等)

    日常办公场合中,除了常规的Excel.Word.PPT等文档外,还有一个不可忽略的文件格式是pdf格式,而对于想从pdf文件中获取信息时,常规方法将变得非常痛苦和麻烦.此篇给大家送一pdf文件提取信息 ...

  8. InstantiationException:mybatis.spring.transaction.SpringManagedTransactionFactory

    问题表现 Error creating bean with name 'sqlSessionFactory' Invocation of init method failed; nested exce ...

  9. 二、C#中数据库连接是用sqlconection 而access是用oledb对象例如:

    OleDBConnection conn =new OleDBConnection();(简单记一下) 重点是研究winform 中combobox 与datagridview 的联动问题: 首先是c ...

  10. Docker volume speed up npm install

    上一节决定在Jenkins中采用Docker作为构建环境,于是就可以为所欲为的使用各种node版本编译我们的项目.解决了版本切换问题.然而,Docker设计的目的就是纯净的执行环境,因此每次运行doc ...