精华内容
下载资源
问答
  • Java的反射(reflection)机制是指在程序的...这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。//User类,子类User user = new User();//Parent类,User的父类Parent...

    Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。

    //User类,子类

    User user = new User();

    //Parent类,User的父类

    Parent parent = new Parent();

    //获取类的类型Class的三种方式

    Class z = User.class;

    Class c = new User().getClass();

    //动态获取

    Class l = Class.forName("com.zqq.test.User");

    字段操作 Field

    Class c = user.getClass();

    //获取当前字段类所有,不包含父类字段,返回Field数组

    c.getDeclaredFields();

    //获取当前类所有public修饰的字段,含父类public修饰的字段,返回Field数组

    c.getFields();

    //根据名称获取当前类字段 不包括父类,返回Field对象

    c.getDeclaredField("age");

    //根据字段名称获取public修饰的字段,包括父类字段,返回Field对象

    c.getField("pubName");

    //是否可以通过放射访问该字段 可以 true 不可以 false

    Field.isAccessible();

    //设置成可以通过反射访问该字段

    Field.setAccessible(true);

    Demo

    User user = new User();

    user.setName("xiaoxiao");

    user.setAge(18);

    User user1 = new User();

    System.out.println(user == user1);

    System.out.println(user.getClass() == user1.getClass());

    Class c = user.getClass();

    //getDeclaredFields 获取当前字段类所有,不包含父类字段

    for(Field f : c.getDeclaredFields()){

    System.out.println(f.getName());

    }

    // c.getFields() 获取当前类所有public修饰的字段,含父类public修饰的字段

    for(Field f : c.getFields()){

    System.out.println(f.getName());

    }

    // c.getDeclaredField 根据名称获取当前类字段 不包括父类

    Field field = c.getDeclaredField("age");

    System.out.println("字段信息====:" + field.toString());

    //c.getField(name) 根据字段名称获取public修饰的字段,包括父类字段

    //System.out.println("本身私有字段====age:" + c.getField("age")); // 报错 java.lang.NoSuchFieldException

    System.out.println("本身public字段pubAge======pubAge:" + c.getField("pubAge"));

    System.out.println("父类public修饰字段===========pubName :" + c.getField("pubName"));

    //获取字段的值

    Field nameField = c.getDeclaredField("name");

    System.out.println("是否可以通过反射访问该字段:" + nameField.isAccessible());

    // isAccessible为false时不可以通过反射访问该字段,设置成true

    nameField.setAccessible(true);

    System.out.println("是否可以通过反射访问该字段:" + nameField.isAccessible());

    Object name = nameField.get(user);

    System.out.println("获取到字段的值为:" + name);

    //设置字段的值

    nameField.set(user,"大小小");

    System.out.println(user.getName());

    方法操作 Method

    Class c = User.class;

    //获取public修饰的方法(包括父类),传入方法名称

    c.getMethod("say");

    //获取所有public修饰的方法(包括父类)

    c.getMethods();

    //获取当前类的方法(所有作用域)(不包括父类),传入方法名称

    c.getDeclaredMethod("getName");

    //获取当前类所有方法(不包括父类)

    c.getDeclaredMethods();

    //返回方法返回值类型

    Method.getReturnType();

    //返回方法参数类型

    Method.getParameterTypes();

    //返回方法的修饰符,public、private ...

    Modifier.toString(Method.getModifiers());

    //通过反射调用方法,传入对象的实例,静态方法实例传null

    Method.invoke(new User(),'参数,没有不填');

    //设置可以通过反射访问该方法

    method.setAccessible(true);

    Demo

    Class c = User.class;

    //获取public的方法(包括父类)

    Method method = c.getMethod("say");

    //获取所有public的方法包括父类

    Method[] methods = c.getMethods();

    //获取当前类的方法(所有作用域)(不包括父类)

    method = c.getDeclaredMethod("getName");

    //获取当前类所有方法(不包括父类)

    methods = c.getDeclaredMethods();

    System.out.println(method.toString());

    System.out.println("方法名称:" + method.getName());

    System.out.println("方法返回值类型:" + method.getReturnType());

    System.out.println("方法的参数类型:" + method.getParameterTypes());

    System.out.println("方法的修饰符:" + Modifier.toString(method.getModifiers()));

    //调用方法

    method = c.getMethod("say");

    //传入对象的实例

    method.invoke(new User());

    //调用静态方法,实例传null

    Method statciMethon = c.getMethod("sayStatic");

    statciMethon.invoke(null);

    //调用private修饰的方法,需要设置 Method.setAccessible(true),否则会报错 java.lang.NoSuchMethodException

    method = c.getDeclaredMethod("sayPrivate");

    method.setAccessible(true);

    method.invoke(new User());

    构造方法

    //创建对象 , newInstance只能调用public修饰的无参构造方法,有参或者不是public修饰则创建不了对象

    User user = User.class.newInstance();

    user.setName("zqq");

    System.out.println(user.toString());

    //Java的反射API提供了Constructor对象,它包含一个构造方法的所有信息,可以创建一个实例,可以调用任意构造方法

    Constructor constructor = User.class.getDeclaredConstructor(String.class);

    User u = (User) constructor.newInstance("zqqqqq");

    System.out.println(u.toString());

    继承关系 ps:看框架源码的时候可以先获取对象的继承关系

    Class c = User.class;

    //获取父类的Class,返回对象,java单继承

    c.getSuperclass();

    //获取实现的接口,返回数组,java多实现

    c.getInterfaces();

    //isAssignableFrom() 判定此 Class 对象所表示的类或接口与指定的 Class 参数所表示的类或接口是否相同,或是否是其超类或超接口。如果是则返回 true

    Parent.Class.isAssignableFrom(c);

    Demo

    //获取类类型的方式, 类类型 就是类的类型

    Class z = User.class;

    Class c = new User().getClass();

    //传入类的完整类名

    Class l = Class.forName("com.zqq.test.User");

    //这三种方式获取的Class都是同一个Class,因为JVM对每个加载的Class只创建一个Class实例来表示它的类型

    System.out.println(z == c && c == l);

    //获取父类的Class ,阅读源码的时候可以无限往上看看都继承了哪个父类,继承的接口也一样

    Class p = l.getSuperclass();

    System.out.println("父类class:" + p);

    //获取实现的接口

    Class[] interfaces = l.getInterfaces();

    for(Class inter : interfaces){

    System.out.println(inter.toString());

    }

    // instanceof 判断某个实例是否是某个类型

    System.out.println(new User() instanceof com.zqq.test.User);

    // isAssignableFrom() 判定此 Class 对象所表示的类或接口与指定的 Class 参数所表示的类或接口是否相同,或是否是其超类或超接口。如果是则返回 true

    System.out.println(User.class.isAssignableFrom(Parent.class));

    System.out.println(Parent.class.isAssignableFrom(User.class));

    【往期精彩视频】

    展开全文
  • JavaClass对象详解

    2021-02-27 17:59:03
    一、RRTI的概念以及Class对象作用认识Class对象之前,先来了解一个概念,RTTI(Run-Time Type Identification)运行时类型识别,其作用是在运行时识别一个对象的类型和类的信息;这里分两种:传统的”RRTI”,它假定我们...

    一、RRTI的概念以及Class对象作用

    认识Class对象之前,先来了解一个概念,RTTI(Run-Time Type Identification)运行时类型识别,其作用是在运行时识别一个对象的类型和类的信息;

    这里分两种:传统的”RRTI”,它假定我们在编译期已知道了所有类型(在没有反射机制创建和使用类对象时,一般都是编译期已确定其类型,如new对象时该类必须已定义好),另外一种是反射机制,它允许我们在运行时发现和使用类型的信息。在Java中用来表示运行时类型信息的对应类就是Class类,Class类也是一个实实在在的类,存在于JDK的java.lang包中,其部分源码如下:

    public final class Class implementsjava.io.Serializable,GenericDeclaration,Type, AnnotatedElement {private static final int ANNOTATION= 0x00002000;private static final int ENUM = 0x00004000;private static final int SYNTHETIC = 0x00001000;private static native voidregisterNatives();static{

    registerNatives();

    }/** Private constructor. Only the Java Virtual Machine creates Class objects.(私有构造,只能由JVM创建该类)

    * This constructor is not used and prevents the default constructor being

    * generated.*/

    privateClass(ClassLoader loader) {//Initialize final field for classLoader. The initialization value of non-null//prevents future JIT optimizations from assuming this final field is null.

    classLoader =loader;

    }

    Class类被创建后的对象就是Class对象,注意,Class对象表示的是自己手动编写类的类型信息,比如创建一个Shapes类,那么,JVM就会创建一个Shapes对应Class类的Class对象,该Class对象保存了Shapes类相关的类型信息。实际上在Java中每个类都有一个Class对象,每当我们编写并且编译一个新创建的类就会产生一个对应Class对象并且这个Class对象会被保存在同名.class文件里(这里的class对象与下面要讲jvm加载的class对象不一样,个人理解是被JVM加载生成Class对象前的二进制格式的Class对象);

    那为什么需要这样一个Class对象呢?是这样的,当我们new一个新对象或者引用静态成员变量时,Java虚拟机(JVM)中的类加载器子系统会将对应Class对象加载到JVM中,然后JVM再根据这个类型信息相关的Class对象创建我们需要实例对象或者提供静态变量的引用值。需要特别注意的是,手动编写的每个class类,无论创建多少个实例对象,在JVM中都只有一个Class对象,即在内存中每个类有且只有一个相对应的Class对象,挺拗口,通过下图理解(内存中的简易现象图):

    049f7b22e89f6c950901b966c3b4580d.png

    到这我们也就可以得出以下几点信息:

    Class类也是类的一种,与class关键字是不一样的。

    手动编写的类被编译后会产生一个Class对象,其表示的是创建的类的类型信息,而且这个Class对象保存在同名.class的文件中(字节码文件),比如创建一个Shapes类,编译Shapes类后就会创建其包含Shapes类相关类型信息的Class对象,并保存在Shapes.class字节码文件中。

    每个通过关键字class标识的类,在内存中有且只有一个与之对应的Class对象来描述其类型信息,无论创建多少个实例对象,其依据的都是用一个Class对象。

    Class类只存私有构造函数,因此对应Class对象只能有JVM创建和加载

    Class类的对象作用是运行时提供或获得某个对象的类型信息,这点对于反射技术很重要(关于反射稍后分析)。

    二、Class对象的加载及其获取方式

    1.Class对象的加载

    前面我们已提到过,Class对象是由JVM加载的,那么其加载时机是?实际上所有的类都是在对其第一次使用时动态加载到JVM中的,当程序创建第一个对类的静态成员引用时,就会加载这个被使用的类(实际上加载的就是这个类的字节码文件);注意,使用new操作符创建类的新实例对象也会被当作对类的静态成员的引用(构造函数也是类的静态方法),由此看来Java程序在它们开始运行之前并非被完全加载到内存的,其各个部分是按需加载;

    所以在使用该类时,类加载器首先会检查这个类的Class对象是否已被加载(类的实例对象创建时依据Class对象中类型信息完成的),如果还没有加载,默认的类加载器就会先根据类名查找.class文件(编译后Class对象被保存在同名的.class文件中),在这个类的字节码文件被加载时,它们必须接受相关验证,以确保其没有被破坏并且不包含不良Java代码(这是java的安全机制检测),完全没有问题后就会被动态加载到内存中,此时相当于Class对象也就被载入内存了(毕竟.class字节码文件保存的就是Class对象),同时也就可以被用来创建这个类的所有实例对象。

    下面通过一个简单例子来说明Class对象被加载的时机问题(例子引用自Thinking in Java):

    packagecom.zejian;classCandy {static { System.out.println("Loading Candy"); }

    }classGum {static { System.out.println("Loading Gum"); }

    }classCookie {static { System.out.println("Loading Cookie"); }

    }public classSweetShop {public static voidprint(Object obj) {

    System.out.println(obj);

    }public static voidmain(String[] args) {

    print("inside main");newCandy();

    print("After creating Candy");try{

    Class.forName("com.zejian.Gum");

    }catch(ClassNotFoundException e) {

    print("Couldn't find Gum");

    }

    print("After Class.forName(\"com.zejian.Gum\")");newCookie();

    print("After creating Cookie");

    }

    }

    在上述代码中,每个类Candy、Gum、Cookie都存在一个static语句,这个语句会在类第一次被加载时执行,这个语句的作用就是告诉我们该类在什么时候被加载,执行结果:

    inside main

    Loading Candy

    After creating Candy

    Loading Gum

    After Class.forName("com.zejian.Gum")

    Loading Cookie

    After creating Cookie

    Process finished with exit code0

    从结果来看,new一个Candy对象和Cookie对象,构造函数将被调用,属于静态方法的引用,Candy类的Class对象和Cookie的Class对象肯定会被加载,毕竟Candy实例对象的创建依据其Class对象。比较有意思的是 Class.forName("com.zejian.Gum");

    其中forName方法是Class类的一个static成员方法,记住所有的Class对象都源于这个Class类,因此Class类中定义的方法将适应所有Class对象。这里通过forName方法,我们可以获取到Gum类对应的Class对象引用。从打印结果来看,调用forName方法将会导致Gum类被加载(前提是Gum类从来没有被加载过)。

    2.Class对象的获取方式

    Class.forName方法

    通过上述的案例,我们也就知道Class.forName()方法的调用将会返回一个对应类的Class对象,因此如果我们想获取一个类的运行时类型信息并加以使用时,可以调用Class.forName()方法获取Class对象的引用,这样做的好处是无需通过持有该类的实例对象引用而去获取Class对象,如下的第2种方式是通过一个实例对象获取一个类的Class对象,其中的getClass()是从顶级类Object继承而来的,它将返回表示该对象的实际类型的Class对象引用。

    public static voidmain(String[] args) {try{//通过Class.forName获取Gum类的Class对象

    Class clazz=Class.forName("com.zejian.Gum");

    System.out.println("forName=clazz:"+clazz.getName());

    }catch(ClassNotFoundException e){

    e.printStackTrace();

    }//通过实例对象获取Gum的Class对象

    Gum gum = newGum();

    Class clazz2=gum.getClass();

    System.out.println("new=clazz2:"+clazz2.getName());

    }

    注意调用forName方法时需要捕获一个名称为ClassNotFoundException的异常,因为forName方法在编译器是无法检测到其传递的字符串对应的类是否存在的,只能在程序运行时进行检查,如果不存在就会抛出ClassNotFoundException异常。

    Class字面常量

    在Java中存在另一种方式来生成Class对象的引用,它就是Class字面常量,如下:

    //字面常量的方式获取Class对象

    Class clazz = Gum.class;

    这种方式相对前面两种方法更加简单,更安全。因为它在编译器就会受到编译器的检查同时由于无需调用forName方法效率也会更高,因为通过字面量的方法获取Class对象的引用不会自动初始化该类。更加有趣的是字面常量的获取Class对象引用方式不仅可以应用于普通的类,也可以应用用接口,数组以及基本数据类型,这点在反射技术应用传递参数时很有帮助,关于反射技术稍后会分析,由于基本数据类型还有对应的基本包装类型,其包装类型有一个标准字段TYPE,而这个TYPE就是一个引用,指向基本数据类型的Class对象,其等价转换如下,一般情况下更倾向使用.class的形式,这样可以保持与普通类的形式统一。

    boolean.class =Boolean.TYPE;char.class =Character.TYPE;byte.class =Byte.TYPE;short.class =Short.TYPE;int.class =Integer.TYPE;long.class =Long.TYPE;float.class =Float.TYPE;double.class =Double.TYPE;void.class = Void.TYPE;

    前面提到过,使用字面常量的方式获取Class对象的引用不会触发类的初始化,这里我们可能需要简单了解一下类加载的过程,如下:

    f2aa7d0ba0137725794ddd67537e8c7a.png

    加载:类加载过程的一个阶段:通过一个类的完全限定查找此类字节码文件,并利用字节码文件创建一个Class对象

    链接:验证字节码的安全性和完整性,准备阶段正式为静态域分配存储空间,注意此时只是分配静态成员变量的存储空间,不包含实例成员变量,如果必要的话,解析这个类创建的对其他类的所有引用。

    初始化:类加载最后阶段,若该类具有超类,则对其进行初始化,执行静态初始化器和静态初始化成员变量。

    由此可知,我们获取字面常量的Class引用时,触发的应该是加载阶段,因为在这个阶段Class对象已创建完成,获取其引用并不困难,而无需触发类的最后阶段初始化。下面通过小例子来验证这个过程:

    import java.util.*;classInitable {//编译期静态常量

    static final int staticFinal = 47;//非编期静态常量

    static final int staticFinal2 =ClassInitialization.rand.nextInt(1000);static{

    System.out.println("Initializing Initable");

    }

    }classInitable2 {//静态成员变量

    static int staticNonFinal = 147;static{

    System.out.println("Initializing Initable2");

    }

    }classInitable3 {//静态成员变量

    static int staticNonFinal = 74;static{

    System.out.println("Initializing Initable3");

    }

    }public classClassInitialization {public static Random rand = new Random(47);public static void main(String[] args) throwsException {//字面常量获取方式获取Class对象

    Class initable = Initable.class;

    System.out.println("After creating Initable ref");//不触发类初始化

    System.out.println(Initable.staticFinal);//会触发类初始化

    System.out.println(Initable.staticFinal2);//会触发类初始化

    System.out.println(Initable2.staticNonFinal);//forName方法获取Class对象

    Class initable3 = Class.forName("Initable3");

    System.out.println("After creating Initable3 ref");

    System.out.println(Initable3.staticNonFinal);

    }

    }

    执行结果:

    After creating Initable ref47Initializing Initable258Initializing Initable2147Initializing Initable3

    After creating Initable3 ref74

    从输出结果来看,可以发现,通过字面常量获取方式获取Initable类的Class对象并没有触发Initable类的初始化,这点也验证了前面的分析,同时发现调用Initable.staticFinal变量时也没有触发初始化,这是因为staticFinal属于编译期静态常量,在编译阶段通过常量传播优化的方式将Initable类的常量staticFinal存储到了一个称为NotInitialization类的常量池中,在以后对Initable类常量staticFinal的引用实际都转化为对NotInitialization类对自身常量池的引用,所以在编译期后,对编译期常量的引用都将在NotInitialization类的常量池获取,这也就是引用编译期静态常量不会触发Initable类初始化的重要原因。但在之后调用了Initable.staticFinal2变量后就触发了Initable类的初始化,注意staticFinal2虽然被static和final修饰,但其值在编译期并不能确定,因此staticFinal2并不是编译期常量,使用该变量必须先初始化Initable类。Initable2和Initable3类中都是静态成员变量并非编译期常量,引用都会触发初始化。至于forName方法获取Class对象,肯定会触发初始化,这点在前面已分析过。到这几种获取Class对象的方式也都分析完,ok~,到此这里可以得出小结论:

    获取Class对象引用的方式3种,通过继承自Object类的getClass方法,Class类的静态方法forName以及字面常量的方式”.class”。

    其中实例类的getClass方法和Class类的静态方法forName都将会触发类的初始化阶段,而字面常量获取Class对象的方式则不会触发初始化。

    初始化是类加载的最后一个阶段,也就是说完成这个阶段后类也就加载到内存中(Class对象在加载阶段已被创建),此时可以对类进行各种必要的操作了(如new对象,调用静态成员等),注意在这个阶段,才真正开始执行类中定义的Java程序代码或者字节码。

    关于类加载的初始化阶段,在虚拟机规范严格规定了有且只有5种场景必须对类进行初始化:

    使用new关键字实例化对象时、读取或者设置一个类的静态字段(不包含编译期常量)以及调用静态方法的时候,必须触发类加载的初始化过程(类加载过程最终阶段)。

    使用反射包(java.lang.reflect)的方法对类进行反射调用时,如果类还没有被初始化,则需先进行初始化,这点对反射很重要。

    当初始化一个类的时候,如果其父类还没进行初始化则需先触发其父类的初始化。

    当Java虚拟机启动时,用户需要指定一个要执行的主类(包含main方法的类),虚拟机会先初始化这个主类

    当使用JDK 1.7 的动态语言支持时,如果一个java.lang.invoke.MethodHandle 实例最后解析结果为REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄对应类没有初始化时,必须触发其初始化(这点看不懂就算了,这是1.7的新增的动态语言支持,其关键特征是它的类型检查的主体过程是在运行期而不是编译期进行的,这是一个比较大点的话题,这里暂且打住)

    展开全文
  • JAVA类型信息——Class对象一、RTTI概要1、类型信息RTTI:即对象和类的信息,例如类的名字、继承的基类、实现的接口等。2、类型信息的作用:程序员可以在程序运行时发现和使用类型信息。3、RTTI真正含义:运行时,...

    JAVA类型信息——Class对象

    一、RTTI概要

    1、类型信息RTTI:即对象和类的信息,例如类的名字、继承的基类、实现的接口等。

    2、类型信息的作用:程序员可以在程序运行时发现和使用类型信息。

    3、RTTI真正含义:运行时,识别一个对象的类型。

    4、如何在程序运行时识别对象和类的信息?

    1)传统RTTI:即在编译时已知道了所有的类型。

    2)反射机制:在程序运行时发现和使用类的信息。

    5、RTTI的使用

    importjava.util.*;//List支持泛型

    //import java.awt.List;不支持泛型

    importjava.util.Arrays;

    abstractclassShapes{

    voiddraw() {System.out.println(this+".draw()");}

    abstractpublicString toString();

    }

    classCircleextendsShapes{

    publicString toString() {return"Circle";}

    }

    classTriangleextendsShapes{

    publicString toString() {return"Triangle";}

    }

    classSquareextendsShapes{

    publicString toString() {return"Square";}

    }

    classTest{

    publicstaticList getList(){

    List list_aShapes = Arrays.asList(newCircle() ,newSquare(),newTriangle());

    returnlist_aShapes;

    }

    }

    publicclassShape {

    publicstaticvoidmain(String[] args) {

    List list_aShapes = Test.getList();

    for(Shapes ob_aShapes : list_aShapes) {

    ob_aShapes.draw();

    }

    }

    }

    运行结果:Circle.draw()

    Square.draw()

    Triangle.draw()

    结果分析:(1)toString()都继承Object类的toSting(),派生类的toString()都会覆盖基类的该方法。

    (2)Shapes.draw()中的this间接调用toString()。

    (3)假设Test类是服务器端提供给客户端使用的一个类,客户端调用该类的方法(这里main()调用)获得一个泛化引用,显然,客户端并不知道泛化引用中的确切类型,而程序员需要使用到某一个确切类型对象,这时,我们就需要到RTTI。在上面的例子中,我们只是打印出泛化引用的所有类型。

    二、Class对象Class对象概述(1)持有RTTI信息

    (2)每个类都有一个Class对象,每当编译一个新类就产生一个Class对象。

    (3) Class引用总是指向某个Class对象。Class引用表示的就是它所指向的对象的确切类型,而该对象便是Class类的一个对象。

    ()

    forName()(1)获取Class对象的一个引用,但引用的类还没有加载(该类的第一个对象没有生成)就加载了这个类.

    (2)为了产生Class引用,forName()立即就进行了初始化。

    Object-getClass()获取Class对象的一个引用,返回表示该对象的实际类型的Class引用。

    getName()获取全限定的类名(包括包名),即类的完整名字。

    getSimpleName()获取类名(不包括包名)

    getCanonicalName()获取全限定的类名(包括包名)

    isInterface()判断Class对象是否是表示一个接口

    getInterface()返回Class对象,表示Class对象所引用的类所实现的所有接口。

    getSupercalss()返回Class对象,表示Class对象所引用的类所继承的直接基类。应用该方法可在运行时发现一个对象完整的继承结构。

    newInstance()返回一个Oject对象,是实现“虚拟构造器”的一种途径。

    “虚拟构造器”:我不知道你的确切的类型,但无论如何都要正确创建你自己。

    使用该方法创建的类,必须带有默认的构造器。

    cast()接受一个对象为参数,并将其转型为Class引用的类型。该法一般是在无法使用普通转型的情况下使用。

    getClassLoader()返回该类的类加载器。

    getComponentType()返回表示数组组件类型的Class。

    isArray()判定此Class对象是否表示一个数组类。

    类字面常量(1)一种用来生成对Class对象引用的方法。

    (2)相对forName()而言,效率更高,而且不会立即引发初始化。

    (3)方法:className.class;。

    (4)既可用于普通类,也可用于接口、数组、基本数据类型。

    …………等价于…………

    boolean.classBoolean.class

    char.classChar.class

    byte.classByte.class

    short.classShort.class

    int.classInteger.class

    long.classLong.class

    float.classFloat.class

    double.classDouble.class

    void.classVoid.class

    泛化的Class引用(1)实现方法:使用通配符“?”。

    (2)Class>优于Class,即便他们是等价的。

    (3)Class>的好处是明确地告诉编译器你选择了非具体的类版本,而不是由于碰巧或者疏忽而使用了一个非具体的类引用。

    (4)创建一个范围:创建一个Class引用,使它被限定为某种类型;或该类型的任何子类型,< ? extends superClass>;或者该类型的超类,< ? super super sunClassName>

    import java.lang.Class;

    import java.lang.reflect.Constructor;

    interface Iterface1{}

    interface Iterface2{}

    abstract class SuperClass{

    SuperClass(){};

    SuperClass(int i){}

    static {System.out.println("creating SuperClass");}

    }

    class SunClass extends SuperClass implementsIterface1, Iterface2{

    SunClass(){super(1);}

    static {System.out.println("creating SunClass");}

    }

    class SunClass1 extends SuperClass implementsIterface1, Iterface2{

    SunClass1(){super(1);}

    static {System.out.println("creating SunClass1");}

    }

    public class ClassObject {

    static void printInfo(Class cc) {

    System.out.println("Class name:" + cc.getName()

    + "is Interface : " + cc.isInterface()

    +"Simple name : " + cc.getSimpleName()

    + "Canonical name : " + cc.getCanonicalName());

    }

    public static void main(String[] args) {

    System.out.println("/forName()与类字面常量");

    Class ob_aClass = null;

    //对类的引用不引发初始化

    Class ob_cClass = SuperClass.class;

    System.out.println("After creating SuperClass");

    try {

    //立即初始化类

    ob_aClass = Class.forName("rtti.SunClass");

    System.out.println("After creating SunClass");

    System.out.println("///");

    }catch(ClassNotFoundException e){

    System.out.println("Can't find SunClass.");

    System.exit(1);

    }

    printInfo(ob_aClass);

    System.out.println("///Class引用实现的接口///");

    for(Class face : ob_aClass.getInterfaces())

    printInfo(face);

    System.out.println("//Class引用的基类");

    Class ob_bClass = ob_aClass.getSuperclass();

    printInfo(ob_bClass);

    System.out.println("///newInstance()///");

    Object ob_aObject = null;

    try {

    ob_aObject = ob_aClass.newInstance();

    //运行剖出异常newInstance()该法必须由Class.forName()调用

    //ob_aObject = ob_bClass.newInstance();

    }catch(InstantiationException e){

    System.out.println("Can't instante.");

    System.exit(1);

    }catch(IllegalAccessException e){

    System.out.println("Can't access.");

    System.exit(1);

    }

    printInfo(ob_aObject.getClass());

    System.out.println("//Class引用的泛型");

    Class extends SuperClass>ob_dClass = SunClass.class;

    printInfo(ob_dClass);

    Class extends SuperClass>ob_eClass = SunClass1.class;

    printInfo(ob_eClass);

    //没有类型转换(Class super SunClass>),会出错,上位知道原因?

    Class super SunClass>ob_fClass = (Class super SunClass>)

    ob_dClass.getSuperclass();

    printInfo( ob_fClass);

    }

    }

    运行结果:

    creating SuperClass

    creating SunClass

    After creating SunClass

    ///

    Class name:rtti.SunClassis Interface : falseSimple name : SunClassCanonical name : rtti.SunClass

    ///Class引用实现的接口///

    Class name:rtti.Iterface1is Interface : trueSimple name : Iterface1Canonical name : rtti.Iterface1

    Class name:rtti.Iterface2is Interface : trueSimple name : Iterface2Canonical name : rtti.Iterface2

    //Class引用的基类

    Class name:rtti.SuperClassis Interface : falseSimple name : SuperClassCanonical name : rtti.SuperClass

    ///newInstance()///

    Class name:rtti.SunClassis Interface : falseSimple name : SunClassCanonical name : rtti.SunClass

    //Class引用的泛型

    Class name:rtti.SunClassis Interface : falseSimple name : SunClassCanonical name : rtti.SunClass

    Class name:rtti.SunClass1is Interface : falseSimple name : SunClass1Canonical name : rtti.SunClass1

    Class name:rtti.SuperClassis Interface : falseSimple name : SuperClassCanonical name : rtti.SuperClass

    展开全文
  • 目录:通过Class对象可以获取继承关系:1.Class getSuperclass():获取父类类型;(单继承)2.Class[] getInterfaces():获取当前类实现的所有接口;(多实现)3.通过Class对象的isAssignableFrom()方法,判断Class向上...

    目录:

    通过Class对象可以获取继承关系:

    1.Class getSuperclass():获取父类类型;(单继承)

    2.Class[] getInterfaces():获取当前类实现的所有接口;(多实现)

    3.通过Class对象的isAssignableFrom()方法,判断Class向上转型是否可以实现。

    1.获取父类类型

    public class Main {

    public static void main(String[] args) throws Exception {

    Class i = Integer.class;

    Class n = i.getSuperclass();

    System.out.println(n);

    Class o = n.getSuperclass();

    System.out.println(o);

    System.out.println(o.getSuperclass());

    }

    }

    输出:

    class java.lang.Number

    class java.lang.Object

    null

    Integer的父类类型是Number,Number的父类是Object,Object的父类是null。除Object外,其他任何非interface的Class都必定存在一个父类类型。

    2.获取当前类实现的所有接口

    public class Main {

    public static void main(String[] args) throws Exception {

    Class s = Integer.class;

    Class[] is = s.getInterfaces();

    for (Class i : is) {

    System.out.println(i);

    }

    }

    }

    输出Integer实现的接口有:

    java.lang.Comparable

    java.lang.constant.Constable

    java.lang.constant.ConstantDesc

    3.判断Class向上转型

    在非反射调用中,当我们判断一个实例是否是某个类型时,正常情况下,使用instanceof操作符:

    Object n = Integer.valueOf(123);

    boolean isDouble = n instanceof Double; // false

    boolean isInteger = n instanceof Integer; // true

    boolean isNumber = n instanceof Number; // true

    boolean isSerializable = n instanceof java.io.Serializable; // true

    如果是两个Class实例,要判断一个向上转型是否成立,可以调用isAssignableFrom():

    // Integer i = ?

    Integer.class.isAssignableFrom(Integer.class); // true,因为Integer可以赋值给Integer

    // Number n = ?

    Number.class.isAssignableFrom(Integer.class); // true,因为Integer可以赋值给Number

    // Object o = ?

    Object.class.isAssignableFrom(Integer.class); // true,因为Integer可以赋值给Object

    // Integer i = ?

    Integer.class.isAssignableFrom(Number.class); // false,因为Number不能赋值给Integer

    展开全文
  • Java面向对象(一) 封装 在面向对象程式设计方法中,封装(英语:Encapsulation)是指,一种将抽象性函式接口的实作细节部份包装、隐藏起来的方法。 封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类...
  • java的反射机制提供了两种方法:getDeclaredFields() :该方法能获取到本类的所有属性,包括private,protected和public,但不能获取继承的父类的属性。getFields():既能获取本类的属性也能得到父类的属性,但...
  • 项目中导入大量枚举对象,用来定义常量。随着带来一个问题,就是每个枚举类都需要通过key来获取对应枚举的需求。public enum ExamType {CRAFT(1, "草稿"),PASSING(2, "待审核");private int value;private String ...
  • java面向对象的三大特征:封装,继承,多态1、封装:java中的封装是指一个类把自己内部的实现细节进行隐藏,,只暴露对外的接口(getter和setter)方法,封装又分为属性的封装和方法的封装。封装又分为属性...
  • java class对象

    2021-03-05 22:30:51
    RTTI 运行时类型信息 与 Reflect 反射RTTI,Run Time Type Information,运行时类型信息。要理解RTTI在java中的工作...每当编写并编译了一个新类,就会产生一个Class对象,被保...文章yichudu2015-02-02953浏览量...
  • 获取类的继承关系,并且了解interface实例的动动态建立
  • 获取java对象

    2021-03-06 22:16:39
    ResultSet 接口方法ResultSet 接口方法(由蚂蚁了了整理!)方法返回值类型 方法booleanabsolute(introw)JDBC 2.0。将游标移至结果集中的给定行号。...文章李博 bluemind2017-12-051772浏览量jsp九大内置对象与se...
  • getClass()或类 – 文字 – Foo.class返回一个Class对象,它包含一些关于类的元数据:>名称>包>方法>字段>构造函数>注释和一些有用的方法,如铸造和各种检查(isAbstract(),isPrimitive(...
  • java面向对象-继承

    2021-03-05 22:15:08
    1、继承(inheritance)继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新...2、我们可以把JAVA中的类分为以下三种:类:使用class定义且不含有抽象方法的类。抽象类:使用abstract...
  • ClassUtil.javapackage pri.lime.main;import java.io.File;import java.io.IOException;import java.net.URL;import java.util.ArrayList;import java.util.Enumeration;/*** 查找指定路径下面实现指定接口的全部类...
  • 首先知道:Class clzz=getClass().getSuperclass();...而Type是JAVA语言中所有类型的公共父接口,Class类是其直接实现类。获取父类泛型类型:Type type=getClass().getGenericSuperclass();ParameterizedType pt =...
  • Class”类众所周知Java有个Object 类,是所有Javaclasses的继承根源,其内声明了数个应该在所有Javaclass中被改写的methods:hashCode()、equals()、clone()、toString()、getClass()等。其中getClass()返回一个...
  • Java反射定义、获取Class三种方法

    千次阅读 2021-02-13 01:31:52
    Class类是反射机制的起源,我们得到Class对象有3种方法:第一种:通过类名获得Class> class = ClassName.class;第二种:通过类名全路径获得Class> class = Class.forName("类名全路径")...
  • Java面向对象三大特性(封装、继承、多态)

    千次阅读 多人点赞 2021-05-19 20:59:41
    面向对象的语言有三大特性:封装、继承、多态。三大特性是面向对象编程的核心。下面就来介绍一下面向对象的三大特性。 如果想了解面向对象可以看一下这一篇博客类和对象 一、封装 1.封装的概念 在我们写代码的时候...
  • 项目中使用一个工具类,需要传入类的class来确定返回的结果类型,比如: public <T> convert(Object obj,Class<...简单看了下里边的思路跟网上说的获取泛型类型需要通过继承一个父类是一样的解决方法。 Typ.
  • /*** 获取一个类和其父类的所有属性** @param clazz* @return*/public static List findAllFieldsOfSelfAndSuperClass(Class clazz) {Field[] fields = null;List fieldList = Lists.newArrayList();while (true) {...
  • importjava.io.File;importjava.io.IOException;importjava.net.URL;importjava.util.ArrayList;importjava.util.Enumeration;/*** 查找指定路径下面实现指定接口的全部类**@authorLiang** 2017年5月9日*/pu...
  • java抽象类 继承

    千次阅读 2021-03-08 06:02:32
    关于java抽象类 继承的搜索结果回答抽象类和接口的区别:默认的方法实现抽象类可以有默认的方法实现完全是抽象的。接口根本不存在方法的实现。抽象类中可以有已经实现了的方法,也可以有被abstract修饰的方法(抽象...
  • Java的基本思想之一是万事万物即对象,类也是一...//java.lang.Class类中的的主要方法如下下面是Java1.8 API中java.lang.Class类中的方法:va.lang中Class Class java.lang.Object继承java.lang.Class类型参数:T ...
  • Java代码publicclassTestClass{publicstaticvoidmain(String[]args){try{//测试Class.forName()ClasstestTypeForName=Class.forName("TestClassType");System.out.println("testForName--"+testTypeForName);//...
  • Java 面向对象(转)

    2021-02-26 20:21:58
    转自:http://blog.sina.com.cn/s/blog_83c5190f01010ate.html1、我们可以把JAVA中的类分为以下三种:类:使用class定义且不含有抽象方法的类。抽象类:使用abstract class定义的类,它可以含有,也可以不含有抽象...
  • 存在继承关系的父类对象和子类对象之间也可以在一定条件之下相互转换。这种转换需要遵守以下原则:1.子类对象可以被视为是其父类的一个对象2.父类对象不能被当作是某一个子类的对象。3.如果一个方法的形式参数定义的...
  • 获取继承关系

    2021-03-04 07:43:29
    当我们获取到某个Class对象时,实际上就获取到了一个类的类型:Class cls = String.class; // 获取到String的Class还可以用实例的getClass()方法获取:String s = "";Class cls = s.getClass(); // s是String,因此...
  • Java面向对象 - 封装、继承和多态

    千次阅读 2021-01-16 10:39:55
    3.实现Java封装的步骤。 什么是封装 封装:就是隐藏对象的属性和实现细节,仅对外提供公共访问方式。 封装时的权限控制符区别如下: 封装的意义 对于封装而言,一个对象它所封装的是自己的属性和方法,所以它是不...
  • Class entityClass = (Class ) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];getGenericInterfaces()和getGenericSuperclass()getInterfaces()和getSuperclass()先来看看...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 453,559
精华内容 181,423
关键字:

java获取对象的继承class

java 订阅