黑马程序员-【反射】

                           ------- android培训java培训、期待与您交流! ----------

反射的概念

   

    反射的引入:

    Object obj = new Student();

    若程序运行时接收到外部传入的一个对象,该对象的编译类型是Object,但程序又需要调用该对象运行类型的方法:

       1.若编译和运行类型都知道,使用 instanceof判断后,强转。

       2.编译时根本无法预知该对象属于什么类,程序只能依靠运行时信息来发现对象的真实信息,这时就必须使用反射了。

       3.要是想得到对象真正的类型,就得使用反射。

     简单的来说,反射机制指的是程序在运行时能够获取自身的信息。在java中,只要给定类的名字,那么就可以通过反射机制来获

类的所有信息。

 

反射的优缺点

    

   静态编译:在编译时确定类型,绑定对象,即通过。  

   动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。

   优点:是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发。

   缺点:影响系统性能

 

Class类

 

     java中的类是用来描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则是由这个类的实例

象来确定的,不同的实例对象有不同的属性值。java中所有的类也是一类事物,有其共性,都有所属的包,类名,属性的访问权

限,字段,方法等信息。我们对此进行抽象提取用于描述类的共性内容,这就出现了一个特有的类Class类。

 

    Class对象封装了一个java类中定义的成员变量、成员方法、构造方法、类名、包名等。

 

     一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,所以

它们在内存中的内容是不同的
  

    获得class类的方式:

         1、调用某个类的class属性获取Class对象,如Date.class会返回Date类对应的Class对象(其实就是得到一个类的一份字节码文件);

         2、调用某个对象的getClass()方法。该方法属于Object类;Class<?> clz = new Date().getClass();

         3、使用Class类的forName(String className)静态方法,className表示全限定名;如String的全限定名:java.lang.String;

 例子:

 

public class ClassDemo1 {
	public static void main(String[] args) throws Exception {
		//获得Class对象的方法(三种)
		//一:调用属性
		Class<String> c = String.class;
		System.out.println(c);//打印结果:class java.lang.String    				String.class就表示JVM中一份表示String类的字节码
		Class<String> c2 = String.class;
		System.out.println(c == c2);//true都是String类的字节码  		一个类在虚拟机中只有一份字节码;
		
		//二:使用forName()方法
		//Class cla = Class.forName("String");//ERROR,
		Class<String> cla = 															(Class<String>)Class.forName("java.lang.String");//必须用上全限定名,否则报错
		System.out.println(c == cla);//true
		
		//三:利用对象调用Object的getClass方法;
		Class c3 = new String().getClass();
		System.out.println(c == c3);//ture
	}
}


      预定义的Class对象:基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void通过class属性

也表示为 Class 对象;

  

利用class获取类的属性信息

    

class A {	
}
interface B{
}
interface C{
}

public class BaseDemo3 extends A implements B,C{
	
	//内部类
	public class C{}
	public interface D{}
	public static void main(String[] args) {
		//类可以,接口也可以
		Class<BaseDemo3> c = BaseDemo3.class;
		System.out.println(c);//class junereflect624.BaseDemo3

		//得到包名
		System.out.println(c.getPackage());//package junereflect624

		//得到全限定名
		System.out.println(c.getName());//junereflect624.BaseDemo3
		
		//得到类的简称
		System.out.println(c.getSimpleName());//BaseDemo3
		
		//得到父类
		/**
		 * Class<? super T> getSuperclass() 此处super表示下限
          		返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class。 
		 */
		System.out.println(c.getSuperclass().getSimpleName());//A,先获取父类,再获取父类的简称
		
		//得到接口
		System.out.println(c.getInterfaces());//[Ljava.lang.Class;@1b60280
		Class[] arr = c.getInterfaces();
		for (Class cla : arr) {
			System.out.println(cla);//interface junereflect624.B   interface junereflect624.C
		}
		
		//获得public修饰的类
		/**
		 * Class<?>[] getClasses() 
     				返回一个包含某些 Class 对象的数组,这些对象表示属于此 Class 对象所表示的类的成员的所有公共类和接口。 (如果内部类前面没有加上public的话那么得不到!)
		 */
		Class[] cl = c.getClasses();
		System.out.println(cl.length);//在内部类没有加上public修饰的时候长度为0,加上就是2(获取的是公共的)
		for (Class class1 : cl) {
			System.out.println(class1);
		}
		
		//获得修饰符
		int i = c.getModifiers();
		System.out.println(i);//常量值1表示public
		System.out.println(Modifier.toString(i));//直接打印出public
	}
}

 


利用Class获得类构造方法Constructor

 

    Constructor类用于描述类中的构造方法

 

    Constructor<T> getConstructor(Class<?>... parameterTypes)

    返回该Class对象表示类的指定的public构造方法;

 

    Constructor<?>[] getConstructors()

    返回该Class对象表示类的所有public构造方法;

 

    Constructor<?>[] getDeclaredConstructors()

    返回该Class对象表示类的所有构造方法,和访问权限无关;

例子:

 

class Emp{
	private String name;
	private int age;
	private Emp() {
	} 
	Emp(String name){
	}
	public Emp(String name,int age){
	}
}

public class ConstructorDemo4 {
	public static void main(String[] args) throws Exception {
		//得到所有的构造器(先得到类)
		Class<Emp> c = Emp.class;
		/**
		 * Constructor<?>[] getConstructors() 
          		返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。 
		 */
		Constructor[] con = c.getConstructors();//前面的修饰符必须是public才可以在这个方法下获取到
		for (Constructor cons : con) {
			System.out.println("c.getConstructors()"+cons);//如果上面的某构造器public去掉,则显示不出
			/**打印
				public junereflect624.Emp(java.lang.String,int)
			 */
		}
		
		//得到指定的构造器,也是必须public
		Constructor c1 = c.getConstructor(String.class,int.class);
		System.out.println(c1);//public junereflect624.Emp(java.lang.String,int)
									 
System.out.println("====================================");
	//现在想获得不受public影响的,getDeclaredConstructors(),暴力反射
		
		con = c.getDeclaredConstructors();
		for (Constructor cons : con) {
						 
System.out.println("c.getDeclaredConstructors()=="+cons);//此时不受修饰符的影响
			/**打印
			 *  public junereflect624.Emp()
				public junereflect624.Emp(java.lang.String)
				public junereflect624.Emp(java.lang.String,int)
			 */
		}
	}
}


 

利用Class获取类的方法Method

 

     Method类用于描述类中的方法

     

      Method getMethod(String name, Class<?> ... parameterTypes)

      返回该Class对象表示类和其父类的指定的public方法;

 

      Method[] getMethods(): 

      返回该Class对象表示类和其父类的所有public方法;

 

      Method getDeclaredMethod(String name, Class<?>... parameterTypes)

      返回该Class对象表示类的指定的方法。和访问权限无关,但不包括继承的方法;

  

       Method[] getDeclaredMethods():

      返回类所有的方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法;

 

例子:

 

class AB{
	protected String name;
	protected String id;
}
@Deprecated
public class MethodDemo5 extends AB{
	void show(){}
	public void say(){}
	private int age;
	public char c;
	private boolean b;
	public static void main(String[] args) throws Exception {
		Class<MethodDemo5> c = MethodDemo5.class;
		//获取所有的(包含父类的方法)public修饰的方法
		Method[] m = c.getMethods();
		for (Method method : m) {
			System.out.println(method);
		}
				
		//获取指定的方法
		Method me = c.getMethod("main", String[].class);
		System.out.println("main "+me);//main public static void junereflect624.MethodDemo5.main(java.lang.String[]) throws java.lang.Exception
		
		//访问所有方法,不受访问权限影响
		m = c.getDeclaredMethods();
		for (Method method : m) {
			System.out.println("不受影响的:"+method);
		}
		
		me = c.getDeclaredMethod("show");
		System.out.println(me);//void junereflect624.MethodDemo.show()

		me = c.getMethod("toString");
		System.out.println(me);//public java.lang.String java.lang.Object.toString()
		
		/**
		 * Method[] getDeclaredMethods() 
		          返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,
		          包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法,只可以对当前类有效
		 */
		/*me = c.getDeclaredMethod("toString");//ERROR,c.getDeclaredMethod()不能得到继承的方法
		System.out.println(me);//public java.lang.String java.lang.Object.toString()
		 */	
		//得到字段
		Field[] f = c.getFields();
		for (Field field : f) {//只得到了public的
			System.out.println("字段"+field);
		}
		
		//特定字段
		Field fi = c.getField("c");//""里面是名称
		System.out.println(fi);//public char junereflect624.MethodDemo.c
		
		//得到不受限定名限定的全部字段
		f = c.getDeclaredFields();
		for (Field field : f) {//得到不受修饰符限定的字段,但是只对当前类有效
			System.out.println("全部字段:"+field);
			/**
			 *  全部字段:private int junereflect624.MethodDemo.age
				全部字段:public char junereflect624.MethodDemo.c
				全部字段:private boolean junereflect624.MethodDemo.b
			 */
		}
		//注释  Annotation
		 Annotation[] a = c.getAnnotations();
		 System.out.println(a.length);
		 for (Annotation annotation : a) {
			System.out.println(annotation);
		}
		 
		 //特定注解
		 Deprecated d = c.getAnnotation(Deprecated.class);
		 System.out.println(d);
	}
}



利用Class获取字段字段Field

 

class Stu{
	public String name;
	public String sex;
	public int age;
	
	public Stu(String name, String sex, int age) {
		super();
		this.name = name;
		this.sex = sex;
		this.age = age;
	}
}

public class ReflectDemo6 {
	public static void main(String[] args) throws Exception {
		Stu s = new Stu("ll", "男", 22);
		
		Class<Stu> c = Stu.class;
		
		Field f = c.getField("name");
		System.out.println(f.get(s));从哪个对象身上取
//	修改对象的值
/**
Field f = c.getField("name");
		f.set(s,"fff");
System.out.println(f.get(s));//从哪个对象身上取 
*/
	}
}


 

利用反射创建对象

   

  1、使用Class对象的newInstance()方法创建该Class对象的实例,此时该Class对象必须要有无参数的构造方法。

  2、使用Class对象获取指定的Constructor对象,再调用Constructor的newInstance()方法创建对象类的实例,此时可以选择使用

 某个构造方法。如果这个构造方法被私有化起来,那么必须先申请访问,将可以访问设置为true;

 例子:

 

class User{
	/*private User(){//将默认的构造方法私有化的话就不可以再创建对象,两种方法都是这样
	}*/
	public String toString() {
		return "User对象创建成功!";
	}
}

public class NewInstanceDemo6 {
	public static void main(String[] args) throws Exception {
		//传统方式创建对象
		 System.out.println(new User());
		 
		 //使用反射的方式
		 Class<User> c = User.class;
		 User u = c.newInstance();(直接newInstance的话必须保证默认的构造方法正常存在,也就是没有被私有化!这是前提条件)
		 System.out.println(u);
	}
}


 

class Per{
	private String name;
	private int age;
	private Per(){	
	}
	private Per(String name){
	}
	public String toString() {
		return "对象!!!";
	}
}

public class NewInstanceDemo7 {
	public static void main(String[] args) throws Exception {
		Class<Per> c = Per.class;
		//System.out.println(c.newInstance());;//证明利用无参的可以
		
		先获得需要被调用的构造器(private 修饰的构造方法)
		Constructor<Per> con = c.getDeclaredConstructor();//调用默认的,什么都不要写
		System.out.println(con);//private junereflect624.Per()
		/*con = c.getDeclaredConstructor(String.class);获取指定的构造方法
		System.out.println(con);//private junereflect624.Per(java.lang.String)*/		
		//现在只需要执行这个构造器,
		con.setAccessible(true);//允许访问
		Per p = con.newInstance();//成功,通过私有的受保护的构造方法创建了对象
		System.out.println("无参构造方法"+p);
		
		con = c.getDeclaredConstructor(String.class);
		System.out.println(con);//private junereflect624.Per(java.lang.String)
			
		con.setAccessible(true);//允许访问
		p = con.newInstance("liuzhao");//成功,通过私有的受保护的构造方法创建了对象
		System.out.println("String构造方法"+p);
	}
}
package junereflect624;

import java.lang.reflect.Constructor;

enum Color{
	RED,BLUE,GREEN;
	private Color(){
	}
}

public class EnumDemo8 {
	public static void main(String[] args) throws Exception {
		Class<Color> c = Color.class;
		
		Constructor<Color> con = c.getDeclaredConstructor();//(错误在这一行发生,就是说对枚举而言这种方法连构造器都获得不了,)编译可以通过,但是运行就通不过了!
		Color co = (Color) con.newInstance();
		System.out.println(co);//失败,证明对枚举而言不行,所以枚举的单例模式更加安全
		System.out.println(c.isEnum());//true是枚举
	}
}



利用反射调用方法

  

 每个Method的对象对应一个具体的底层方法。获得Method对象后,程序可以使用Method里面的invoke方法来执行该底层方法。

 Object invoke(Object obj,Object ... args):obj表示调用底层方法的对象,后面的args表示传递的实际参数


例子:

 

public class InvokeDemo9 {
	public static void main(String[] args) throws Exception {
		
/*	传统方式:
String name = new Dept().show("hello world");
		System.out.println(name);*/
			
/**
		 * Method getMethod(String name, Class<?>... parameterTypes) 
          		返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指			定公共成员方法。 
		    name - 方法名
			parameterTypes - 参数列表 
		 */
		//想要通过反射来调用Dept中的方法
		Class<Dept> c = Dept.class;
		Method m = c.getMethod("show", String.class);
		Object o = m.invoke(c.newInstance(), "hello world");
		System.out.println(o);
		
		//私有化的方法
		m = c.getDeclaredMethod("privateshow");//无参方法
		m.setAccessible(true);
		o = m.invoke(c.newInstance());
		
		//静态方法的调用
		m = c.getMethod("staticshow");
		m.invoke(null);//staticshow为静态方法,不需创建对象,所以这里会是null
	}
}


实现一个小框架,通过配置文件获取要调用的类名

class ReflecTest2 {
	public static void main(String[] args) throws Exception {
		// 应该先直接用ArrayList和HashSet,然后才引入从配置文件读,这样便于学员学习。
		Properties props = new Properties();
		// 先演示相对路径的问题
		// InputStream ips = new FileInputStream("config.properties");
		/*
		 * 一个类加载器能加载.class文件,那它当然也能加载classpath环境下的其他文件,既然它有如此能力,它没有理由不
		 * 顺带提供这样一个方法。它也只能加载classpath环境下的那些文件。注意:直接使用类加载器时,不能以/打头。
		 */
		// InputStream ips =
		// ReflectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/javaenhance/config. //properties");
		// Class提供了一个便利方法,用加载当前类的那个类加载器去加载相同包目录下的文件
		// InputStream ips =
		// ReflectTest2.class.getResourceAsStream("config.properties");
		InputStream ips = ReflectTest2.class.getResourceAsStream("/cn/itcast/javaenhance/config.properties");
		props.load(ips);
		ips.close();

		String className = props.getProperty("className");
		Class clazz = Class.forName(className);

		Collection collection = (Collection) clazz.newInstance();
		// Collection collection = new ArrayList();
		ReflectPoint pt1 = new ReflectPoint(3, 3);
		ReflectPoint pt2 = new ReflectPoint(5, 5);
		ReflectPoint pt3 = new ReflectPoint(3, 3);
		collection.add(pt1);
		collection.add(pt2);
		collection.add(pt3);
		collection.add(pt1);
		System.out.println(collection.size());
	}
}


 

 

  

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值