您的位置:首页 > 其它

反射学习笔记

2016-04-30 10:28 330 查看
说明:深入学习了下反射 http://edu.51cto.com/course/course_id-4798.html 讲的不错

问题1:

1.对象有编译类型和运行类型

Object obj = new Date();

编译类型:Object

运行类型(其实就是obj对象真实的类型):Date

需求:根据对象obj调用Date类中的一个方法,toLocaleString,如何来做?

obj.toLocaleString()代码在编译阶段去编译类型Object中检查是否有该方法,若没有,编译失败.

解决方案1:强制转换obj为Date类型,前提:必须知道对象的真实类型是什么?

Date d = (Date)obj;

d.toLocaleString();//YES

如果我不知道obj的真实类型,那又如何去调用toLolcaeString方法. 如何去做?

问题2:

见下图:

class  XXUtil{

public staic Object getInstance(){
return new Date();
}
}






说明:

Class这个Java类保存的是一个Java类的meta信息(元信息)。一般在反射中使用。

Object类,是所有Java类的根。包括Class类。





Class类:用于描述一切类/接口.枚举是一种类,注解是一种接口

Class实例:就是指JVM中一份字节码

Class类:用于描述一切类/接口.问题:那Class实例到底表示的是哪一份字节码,为了明确区分出Class实例表示的是谁的字节码.Class类提供了泛型

Class<Date> clz1 = Date.class;//clz1表示是Date的字节码

Class<String> clz2 = String.class;//clz2表示的是String的字节码

如何得到Class的实例:

1.类名.class(就是一份字节码)

2.Class.forName(String className);根据一个类的全限定名来构建Class对象

3.每一个对象多有getClass()方法:obj.getClass();返回对象的真实类型

一个类在JVM中只有一份字节码;

第一种方式:数据类型.class

Class<User> clz1 = User.class;

第二种方式: Class.forName(String className);

Class<?> clz2 = Class.forName("cn.itcast.cd.User");

使用?是因为此时Class不知道类,因为传的是字符串



反射很强大,但是耗性能.主要是为了做工具和框架使用的.

第三种方式: 对象.getClass();得到对象的真实类型,每个方法都有所以在Object里

User u = new User();

Class clz3 = u.getClass();

clz1 == clz2 == clz3:因为表示都是JVM中共同的一份字节码(User.class)





new一个类才会把字节码从IO加载到内存。

Java内置9大的Class实例

对于对象来说,可以直接使用对象.getClass()或者Class.forName(className); 类名.class都可以获取Class实例.

但是我们的基本数据类型,就没有类的权限定名,也没有getClass方法.

问题:那么如何使用Class类来表示基本数据类型的Class实例?

byte,short,int,long,char,float,double,boolean ,void关键字

上述8种类型和void关键字,都有class属性.

表示int的Class对象: Class clz = int.class;

表示boolean的Class对象: boolean.class;

void: Class clz = void.class;

所有的数据类型都有class属性,表示都是Class对象.

思考:

int的包装类是Integer

Integer.class ==?== int.class

结果是false,说明是两份字节码.

Integer 和int是同一种数据类型吗? 不是

但是在八大基本数据类型的包装类中都有一个常量:TYPE

TYPE表示的是该包装类对应的基本数据类型的Class实例.

如:Integer.TYPE----->int.class

Integer.TYPE==int.class;//YES

Integer.TYPE == Integer.class;//ERROR





数组的Class实例:

String[] sArr1 = {"A","C"};

String[] sArr2 = {};

String[][] sArr = {};

int[] sArr = {};

表示数组的Class实例:

String[] sArr1 = {"A","C"};

Class clz = String[].class;//此时clz表示就是一个String类型的一位数组类型

所有具有相同元素类型和维数的数组才共享同一份字节码(Class对象);

注意:和数组中的元素没有一点关系.



获取类中的构造器

获取某一个类中的所有的构造器:

1,明确操作的是哪一份字节码对象

2,获取构造器

Class类获取构造器方法:

Constructor类:表示类中构造器的类型,Constructor的实例就是某一个类中的某一个构造器

public Constructor<?>[] getConstructors():该方法只能获取当前Class所表示类的public修饰的构造器

public Constructor<?>[] getDeclaredConstructors():获取当前Class所表示类的所有的构造器,和访问权限无关

public Constructor<T> getConstructor(Class<?>... parameterTypes) :获取当前Class所表示类中指定的一个public的构造器

参数:parameterTypes表示:构造器参数的Class类型

如:public User(String name)

Constructor c = clz.getConstructor(String.class);





public class User {
public User(){};
public User(String name){};
public User(String name,String school){};
}


       System.out.println(Integer.TYPE);
        
        Class<User> clz=User.class;
        Constructor[]cs=clz.getConstructors();
        for (Constructor c : cs) {
            System.out.println(c);
        }
        
        //获取单个构造器
        Constructor c=clz.getDeclaredConstructor(String.class);
        System.out.println(c);




调用构造器,创建对象

Constructor<T>类:表示类中构造器的类型,Constructor的实例就是某一个类中的某一个构造器

常用方法:

public T newInstance(Object... initargs):如调用带参数的构造器,只能使用该方式.

参数:initargs:表示调用构造器的实际参数

返回:返回创建的实例,T表示Class所表示类的类型

如果:一个类中的构造器可以直接访问,同时没有参数.,那么可以直接使用Class类中的newInstance方法创建对象.

public Object newInstance():相当于new 类名();





修改User

public class User {
public User() {
System.out.println("---");
}
public User(String name) {
System.out.println(name);
}
public User(String name, String school) {
System.out.println(name + " " + school);
}
}


public static void main(String[] args) throws Exception {
System.out.println(Integer.TYPE);

Class<User> clz=User.class;
Constructor[]cs=clz.getConstructors();
for (Constructor c : cs) {
System.out.println(c);
}

//获取单个构造器
//泛型
Constructor<User> c=clz.getDeclaredConstructor(String.class);
System.out.println(c);
User u=c.newInstance("abc");

//不带泛型
Constructor c2=clz.getDeclaredConstructor(String.class);
System.out.println(c2);
Object u2=c2.newInstance("abc");
}




Class.forName方式



如果访问不带参数的构造器可以直接用Class的newInstance()方法





修改访问权限为private

public class User {
public User() {
System.out.println("---");
}
private User(String name) {
System.out.println(name);
}
public User(String name, String school) {
System.out.println(name + " " + school);
}
}


报错







Constructor<User> c=clz.getDeclaredConstructor(String.class);
System.out.println(c);
c.setAccessible(true);
User u=c.newInstance("abc");


获取类中的方法

使用反射获取某一个类中的方法:

1.找到获取方法所在类的字节码对象

2.找到需要被获取的方法

Class类中常用方法:

public Method[] getMethods():获取包括自身和继承过来的所有的public方法

public Method[] getDeclaredMethods():获取自身所有的方法(不包括继承的,和访问权限无关)

public Method getMethod(String methodName,

Class<?>... parameterTypes):表示调用指定的一个公共的方法(包括继承的)

参数:

methodName: 表示被调用方法的名字

parameterTypes:表示被调用方法的参数的Class类型如String.class

public Method getDeclaredMethod(String name,

Class<?>... parameterTypes):表示调用指定的一个本类中的方法(不包括继承的)

参数:

methodName: 表示被调用方法的名字

parameterTypes:表示被调用方法的参数的Class类型如String.class





public class User {
public User() {
System.out.println("---");
}
public User(String name) {
System.out.println(name);
}
public User(String name, String school) {
System.out.println(name + " " + school);
}
public void Say(String name) {
System.out.println(name);
}
public void Say(String name, String school) {
System.out.println(name + " " + school);
}
}


Class clz=User.class;
Method[] m=clz.getMethods();
for (Method c : m) {
System.out.println(c);
}
System.out.println("----------------------");
m=clz.getDeclaredMethods();
for (Method c : m) {
System.out.println(c);
}




Method m1=clz.getMethod("Say", String.class);
System.out.println(m1);
Method m2=clz.getMethod("Say", String.class,String.class);
System.out.println(m2);


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: