由浅入深了解反射机制一:Class类

Class类的作用,反射的源头

 在Object类中定义了以下的方法,此方法将被所有子类继承:
 public final Class getClass()
 以上方法返回值的类型是一个Class类,实际上此类是Java反射的源头,
 实际上所谓反射从程序的运行结果来看也很好理解,即:
 可以通过对象反射求出类的名称
 正常方式:引入需要的包、类名称,通过new实例化,取得实例化对象
 反射方式:实例化对象,getClass()方法,取得完整的包、类名称

实例化Class类对象的方法有三种:
 1.通过forName()方法
 2.类.class
 3.对象.getClass()

package org.lxh.demo15.getclassdemo ;
class X{
};
public class GetClassDemo02{
	public static void main(String args[]){
		Class<?> c1 = null ;		// 指定泛型
		Class<?> c2 = null ;		// 指定泛型
		Class<?> c3 = null ;		// 指定泛型
		try{
			// 以下的操作形式是在开发中最常用的一种形式
			c1 = Class.forName("org.lxh.demo15.getclassdemo.X") ;
		}catch(ClassNotFoundException e){
			e.printStackTrace() ;
		}
		c2 = new X().getClass() ;		// 通过Object类中的方法实例化
		c3 = X.class ;	// 通过类.class实例化
		System.out.println("类名称:" + c1.getName())  ;	// 得到类的名称
		System.out.println("类名称:" + c2.getName())  ;	// 得到类的名称
		System.out.println("类名称:" + c3.getName())  ;	// 得到类的名称
	}
};

Class类的使用

Class主要是反射的源头,不光可以取得对象所在类的信息,也可以哦那天通过Class类的方法进行对象的实例化操作,正常情况下,使用new关键字为对象实例化,如果现在已经实例化好了class对象,则就可以通过Class类中提供的

public T newInstance()

              throws InstantiationException,

                     IllegalAccessException

 

package org.lxh.demo15.instancedemo ;
class Person{
	private String name ;	// name属性
	private int age ;		// age属性
	public void setName(String name){
		this.name = name ;
	}
	public void setAge(int age){
		this.age = age ;
	}
	public String getName(){
		return this.name ;
	}
	public int getAge(){
		return this.age ;
	}
	public String toString(){	// 覆写toString()方法
		return "姓名:" + this.name + ",年龄:" + this.age  ;
	}
};
public class InstanceDemo01{
	public static void main(String args[]){
		Class<?> c = null ;		// 声明Class对象
		try{
			c = Class.forName("org.lxh.demo15.instancedemo.Person") ;
		}catch(ClassNotFoundException e){
			e.printStackTrace() ;
		}
		Person per = null ;	// 声明Person对象
		try{
			per = (Person)c.newInstance() ;	// 实例化对象
		}catch(Exception e){
			e.printStackTrace() ;
		}
		per.setName("李兴华") ;		// 设置姓名
		per.setAge(30) ;				// 设置年龄
		System.out.println(per) ;	// 内容输出,调用toString()
	}
};

通过以上代码,可以发现,即使不使用关键字new对象也可以进行实例化操作,反射的作用。但是,在使用以上操作的时候有一点要注意,在操作类中必须存在无参构造方法,否则无法实例化。

package org.lxh.demo15.instancedemo ;
class Person{
	private String name ;	// name属性
	private int age ;		// age属性
	public Person(String name,int age){
		this.setName(name) ;
		this.setAge(age);
	}
	public void setName(String name){
		this.name = name ;
	}
	public void setAge(int age){
		this.age = age ;
	}
	public String getName(){
		return this.name ;
	}
	public int getAge(){
		return this.age ;
	}
	public String toString(){	// 覆写toString()方法
		return "姓名:" + this.name + ",年龄:" + this.age  ;
	}
};
public class InstanceDemo02{
	public static void main(String args[]){
		Class<?> c = null ;		// 声明Class对象
		try{
			c = Class.forName("org.lxh.demo15.instancedemo.Person") ;
		}catch(ClassNotFoundException e){
			e.printStackTrace() ;
		}
		Person per = null ;	// 声明Person对象
		try{
			per = (Person)c.newInstance() ;	// 实例化对象
		}catch(Exception e){
			e.printStackTrace() ;
		}
		per.setName("李兴华") ;		// 设置姓名
		per.setAge(30) ;				// 设置年龄
		System.out.println(per) ;	// 内容输出,调用toString()
	}
};

出现以下错误:

java.lang.ClassNotFoundException: org.lxh.demo15.instancedemo.Person
	at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:188)
	at fanshe.InstanceDemo01.main(InstanceDemo01.java:29)
java.lang.NullPointerException
	at fanshe.InstanceDemo01.main(InstanceDemo01.java:35)
Exception in thread "main" java.lang.NullPointerException
	at fanshe.InstanceDemo01.main(InstanceDemo01.java:39)

所以说,发现,使用以上的方式实际上还是需要类中构造方法的支持,符合于对象的实例化要求。如果要想解决这样的问题,则必须明确的指定要调用的构造方法,并传递参数,但是从实际的开发角度讲,一般使用反射实例化对象的时候,类中都最好存在一个无参构造,这样的操作比较合理。

如果要想调用有参,则必须按照以下的步骤进行:

扫描二维码关注公众号,回复: 5963658 查看本文章
  1. 通过Class类中的getConstructors()取得本类中的全部构造方法。
  2. 向构造方法中传递一个对象数组进去,里面包含了构造方法中锁需的各个参数。
  3. 之后通过Constructor实例化对象

在Constructor类中存在一个方法:

public T newInstance(Object... initargs)

              throws InstantiationException,

                     IllegalAccessException,

                     IllegalArgumentException,

                     InvocationTargetException

传递初始化参数,以进行对象的实例化操作。

package org.lxh.demo15.instancedemo ;
import java.lang.reflect.Constructor ;	// 导入反射机制包
class Person{
	private String name ;	// name属性
	private int age ;		// age属性
	public Person(String name,int age){
		this.setName(name) ;
		this.setAge(age);
	}
	public void setName(String name){
		this.name = name ;
	}
	public void setAge(int age){
		this.age = age ;
	}
	public String getName(){
		return this.name ;
	}
	public int getAge(){
		return this.age ;
	}
	public String toString(){	// 覆写toString()方法
		return "姓名:" + this.name + ",年龄:" + this.age  ;
	}
};
public class InstanceDemo03{
	public static void main(String args[]){
		Class<?> c = null ;		// 声明Class对象
		try{
			c = Class.forName("org.lxh.demo15.instancedemo.Person") ;
		}catch(ClassNotFoundException e){
			e.printStackTrace() ;
		}
		Person per = null ;	// 声明Person对象
		Constructor<?> cons[] = null ;
		cons = c.getConstructors() ;
		try{
			per = (Person)cons[0].newInstance("李兴华",30) ;	// 实例化对象
		}catch(Exception e){
			e.printStackTrace() ;
		}
		System.out.println(per) ;	// 内容输出,调用toString()
	}
};

但是,从实际角度看,如果要使用反射进行对象的实例化操作,最好在类中存在无参构造。

总结:

在使用Class实例化对象的时候必须保证类中存在一个无参构造,否则无法使用。

如果要想调用有参构造进行对象的实例化操作,则必须使用constructor类完成,此类表示构造方法,并通过可变参数传递要求的内容。

 

 

 

 

猜你喜欢

转载自blog.csdn.net/weixin_42759988/article/details/89433092
今日推荐