Java 读书笔记 14.1-14.6 RTTI

    xiaoxiao2021-03-25  100

    RTTI

    Runtime Type Information 好吧,时隔多日我又来啃这块骨头了;

    RTTI顾名思义 运行时类型信息;编译的时候不知道,只有当具体运行时才知道是什么类型信息;Java编程思想好像也没说是怎么具体实现的;我也只能管中窥豹了;

    首先,我们知道多态,那么多态是啥呢? 维基百科说: 多态也可定义为“一种将不同的特殊行为和单个泛化记号相关联的能力”

    这就让我想起了继承关系;不论是哪个子类都可以用父类表示;编译时是父类,运行时就变成子类了;这就是RTTI了;厉害吧;

    Class对象

    首先想知道Class对象是什么,必须清楚类,类实例化之后形成一个对象; 这是我们常见的:类和对象?那么类是什么?对于虚拟机来说,他怎么区别这个对象和那个对象不一样呢? 这就靠类对象了;通过类对象,我们就知道“类型”; 举个例子;我们说狮子,一般是一个名词,指代一种生物,某个狮子就是狮子这个类的实例化;但是我们的大脑,社会上的文字,是要储存狮子的定义的;这样你知道Class对象是什么了吧;

    class调用顺序

    public class Candy { public Candy() { System.out.println("ccandy"); } { System.out.println("no static"); } static { System.out.println("loading Cnady"); } } public class SweetShop { public static void main(String [] arg) throws ClassNotFoundException { new Candy(); Class a =Class.forName("Class.Gum"); //会直接加载类 } } output: loading Cnady no static ccandy loading Gun

    类字面常量

    想调用类有三种方式

    public class ReflectDemo { public static void main(String[] args) throws ClassNotFoundException { //第一种:Class c1 = Code.class; Class class1=ReflectDemo.class; System.out.println(class1.getName()); //第二种:Class c2 = code1.getClass(); ReflectDemo demo2= new ReflectDemo(); Class c2 = demo2.getClass(); System.out.println(c2.getName()); //第三种:Class c3 = Class.forName("com.trigl.reflect.Code"); Class class3 = Class.forName("com.tengj.reflect.ReflectDemo"); System.out.println(class3.getName()); } }

    第一种的Code.class又叫做类字面常量,好处是不会直接初始化class对象,仅仅是加载; 使用类的准备工作有 1. 加载 2. 链接 3. 初始化,由于java很懒,所以都是啥时候用到啥时候加载,所以直接的forName就有点不好玩了;初始化要延迟到静态方法被调用,(所以构造函数也是静态方法),或者非常数讲台域被引用的时候;

    泛化的class引用

    简单地说就是class引用带了类型,只接受这种,或者一部分的class对象;instance与instanceof,简单说一个要比名字,另一个比的是class对象,对象可以动态传参,所以就方便许多;instance和class比较时的区别 instance会考虑继承;即:麻雀是鸟,但是class不会这么比,麻雀!=鸟;

    反射

    其实就是通过class对象来获取类中的相关内容比如获取一个方法 以下代码来源:”

    public class Person { private String name; private int age; private String msg="hello wrold"; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person() { } private Person(String name) { this.name = name; System.out.println(name); } public void fun() { System.out.println("fun"); } public void fun(String name,int age) { System.out.println("我叫"+name+",今年"+age+"岁"); } } public class ReflectDemo { public static void main(String[] args){ try { Class c = Class.forName("com.tengj.reflect.Person"); Object o = c.newInstance(); Method method = c.getMethod("fun", String.class, int.class); method.invoke(o, "tengj", 10); } catch (Exception e) { e.printStackTrace(); } } }

    或者获取方法组

    public class ReflectDemo { public static void main(String[] args){ try { Class c = Class.forName("com.tengj.reflect.Person"); Method[] methods = c.getDeclaredMethods(); for(Method m:methods){ String methodName= m.getName(); System.out.println(methodName); } } catch (Exception e) { e.printStackTrace(); } } } public class ReflectDemo { public static void main(String[] args){ try { Class c = Class.forName("com.tengj.reflect.Person"); //获取成员变量 Field field = c.getDeclaredField("msg"); //因为msg变量是private的,所以不能用getField方法 Object o = c.newInstance(); field.setAccessible(true);//设置是否允许访问,因为该变量是private的,所以要手动设置允许访问,如果msg是public的就不需要这行了。 Object msg = field.get(o); System.out.println(msg); } catch (Exception e) { e.printStackTrace(); } } } public class ReflectDemo { public static void main(String[] args){ try { Class c = Class.forName("com.tengj.reflect.Person"); //获取构造函数 Constructor constructor = c.getDeclaredConstructor(String.class); constructor.setAccessible(true);//设置是否允许访问,因为该构造器是private的,所以要手动设置允许访问,如果构造器是public的就不需要这行了。 constructor.newInstance("tengj"); } catch (Exception e) { e.printStackTrace(); } } }

    ps:无关思想的细节就不要深究了;

    接口与类型信息

    1.通过使用反射,即使实现包的访问权限,仍旧可以到达并调用所有方法,甚至是private方法。如果知道方法名,就可以在其Method对象上调用setAccessible(true),然后通过invoke()方法来使用该方法。 2.final域实际上在遭遇修改时是安全的。运行时系统会在不抛异常的情况下接受任何修改尝试,但实际上不会发生任何修改

    转载请注明原文地址: https://ju.6miu.com/read-5081.html

    最新回复(0)