JAVA之Class类与反射总结

原文地址为: JAVA之Class类与反射总结

         JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为JAVA语言的反射机制。

 

1.取得Class类的对象的三种方法

      取得Class对象:public final Class<?> getClass(),反射之中的所有泛型都定义为?,返回值都是Object。

  • 通过Object类的getClass()方法取得
<span style="color:#000000;">class Person{}
public class TestDemo{
public static void main(String[] args) throws Exception{
Person per = new Person();
Class<?> cls = per.getClass();
System.out.println(cls.getName());
}
}</span>

 

  • 使用“类.Class”取得
<span style="font-size:12px;"> class Person{}
public class TestDemo{
public static void main(String[] args) throws Exception{
Class<?> cls = Person.class;
System.out.println(cls.getName());
}
}</span>

 

  • 使用Class类内部定义的一个static方法

    取得Class类对象:public static Class<?>forName(String className) throws ClassNotFoundException

class Person{}
public class TestDemo{
public static void main(String[] args) throws Exception{
Class<?> cls = Class.forName("Person");//取得Class对象
System.out.println(cls.getName());
}
}


2.通过反射实例化对象

    通过反射实例化对象:public T newInstance () throws InstantiationException,IllegalAccessException

class Person{
public String toString(){
return "Person Class Instance.";
}
}
public class TestDemo{
public static void main(String[] args) throws Exception{
Class<?> cls = Class.forName("Person");//取得Class对象
Object obj = cls.newInstance(); //实例化对象,和使用关键字new一样
Person per = (Person) obj ; //向下转型
System.out.println(per);
}
}


范例:工厂模式

<span style="font-size:12px;">interface Fruit{
public void eat();
}
class Apple implements Fruit{
public void eat(){
System.out.println("吃苹果。");
}
}
class Factory{
public static Fruit getInstance(String className){
if("apple".equals(className)){
return new Apple();
}
return null;
}
}
public class FactoryDemo {
public static void main(String[] args) {
Fruit f = Factory.getInstance("apple");
f.eat();
}
}</span>


    在这个工厂设计模式之中有一个最大的问题:如果现在接口的子类增加了,那么工厂类肯定需要修改,这是它所面临的最大问题,而这个最大问题造成的关键性病因是new,那么如果说现在不使用关键字new了,变为了反射机制呢?

 

interface Fruit{
public void eat();
}
class Apple implements Fruit{
public void eat(){
System.out.println("吃苹果。");
}
}
class Orange implements Fruit{
public void eat(){
System.out.println("吃橘子。");
}
}
class Factory{
public static Fruit getInstance(String className){
Fruit f = null ;
try {
f = (Fruit)Class.forName(className).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return f ;
}
}
public class FactoryDemo {
public static void main(String[] args) {
Fruit f = Factory.getInstance("Orange");
f.eat();
}
}


3.调用构造方法

编号

方法名称
返回值类型
说明

1

getConstructors()

Constructor数组

获取所有权限为public的构造方法

2

getConstructor(Class<?>…parameterTypes)

Constructor对象

获取权限为public的指定构造方法

3

getDeclaredConstructors()

Constructor数组

获得所有构造方法,按声明顺序返回

4

getDeclaredConstructor(Class<?>…parameterTypes)

Constructor对象

获得指定的构造方法

<span style="font-size:12px;">import java.lang.reflect.Constructor;
class Person{
public Person(){}
public Person(String name){}
public Person(String name , int age){}
}
public class TestDemo{
public static void main(String[] args) throws Exception{
Class<?> cls = Class.forName("Person");//取得Class对象
Constructor<?> cons [] = cls.getConstructors(); //取得全部构造
for(int x = 0 ; x < cons.length ; x ++){
System.out.println(cons[x]);
}
}
}</span>


范例:调用有参数的构造方法

import java.lang.reflect.Constructor;
class Person{
private String name;
private int age ;
public Person(String name , int age){
this.name = name ;
this.age = age ;
}
public String toString(){
return "Person [name="+name+",age="+age+"]" ;
}
}
public class TestDemo{
public static void main(String[] args) throws Exception{
Class<?> cls = Class.forName("Person");//取得Class对象
//取得指定参数类型的构造方法
Constructor<?> cons = cls.getConstructor(String.class,int.class);
Object obj = cons.newInstance("张三",20);//为构造方法传递参数
System.out.println(obj);
}
}


4.调用普通方法

编号

 
方法名称
 
返回值类型
 
说明

1

getMethods()

Method数组

获取所有权限为public的方法

2

getMethod(String name,Class<?>…parameterTypes)

Method对象

获取权限为public的指定方法

3

getDeclaredMethods()

Method数组

获得所有方法,按声明顺序返回

4

getDeclaredMethod(String name,Class<?>…parameterTypes)

Method对象

获得指定的方法

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
class Person{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class TestDemo{
public static void main(String[] args) throws Exception{
Class<?> cls = Class.forName("Person");//取得Class对象
Method met [] = cls.getMethods();
for(int x = 0 ; x < met.length ; x ++){
System.out.println(met[x]);
}
}
}


    取得了Method类对象之后有一个最大的功能,就是可以利用反射调用类中的方法。调用方法:

public Object invoke(Object obj,Object…args) throws IllegalAccessException,IllegalArgumentException,InyocationTargetException

import java.lang.reflect.Method;
class Person{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class TestDemo{
public static void main(String[] args) throws Exception{
Class<?> cls = Class.forName("Person");//取得Class对象
Object obj = cls.newInstance();
String attribute = "name"; //要调用类之中的属性
Method setMet = cls.getMethod("set"+initcap(attribute),String.class);
//setName()
Method getMet = cls.getMethod("get"+initcap(attribute));
//getName()
setMet.invoke(obj, "张三");//等价于:Person对象.setName("张三");
System.out.println(getMet.invoke(obj));
//等价于:Person对象.getName()
}
public static String initcap(String str){
return str.substring(0,1).toUpperCase().concat(str.substring(1));
}
}


5.调用成员

编号

方法名称
 
返回值类型
说明

1

getFields()

Field数组

获取所有权限为public的成员变量

2

getField(String name)

Field对象

获取权限为public的指定成员变量

3

getDeclaredFields()

Field数组

获得所有成员变量,按声明顺序返回

4

getDeclaredField(String name)

Field对象

获得指定的构造方法

<span style="font-size:12px;">import java.lang.reflect.Field;
import java.lang.reflect.Method;
class Person{
private String name;
}
public class TestDemo{
public static void main(String[] args) throws Exception{
Class<?> cls = Class.forName("Person");//取得Class对象
Field field [] = cls.getDeclaredFields();
for(int x = 0 ; x < field.length ; x++) {
System.out.println(field[x]);
}
}
}</span>


在Field类之中提供了两个方法:

  • 设置属性内容(类似于:对象.属性 = 内容):
    public void set(Object obj,Object value) throws IllegalArgumentExcepiton,IllegalAccessException ;
  • 取得属性内容(类似于:对象.属性):
    public Object get(Object obj) throws IllegalArgumentException,IllegalAccessException

从类的开发要求而言,一直都强调之中类之中的属性必须封装,所以现在调用之前要想尽一切方法解除封装。

  • 解除封装:public void setAccessible(boolean flag)throws SecurityException;
<span style="font-size:12px;">import java.lang.reflect.Field;
class Person{
private String name;
}
public class TestDemo{
public static void main(String[] args) throws Exception{
Class<?> cls = Class.forName("Person");//取得Class对象
Object obj = cls.newInstance(); //对象实例化属性才会分配空间
Field nameField = cls.getDeclaredField("name"); //找到name属性
nameField.setAccessible(true);
nameField.set(obj,"张三");//Person对象.name = "张三"
System.out.println(nameField.get(obj));
}
}</span>


6.其他可以通过反射访问的主要描述信息

组成部分

访问方法
返回值类型
说明

包路径

getPackage()

Package对象

获得该类的存放路径

类名称

getName()

String对象

获得该类的名称

继承类

getSuperclass()

Class对象

获得该类的继承的类

实现接口

getInterfaces()

Class数组

获得该类实现的所有接口

内部类

getClasses()

getDeclaredClasses()

Class数组

获得所有权限为public的内部类

获得所有内部类

内部类的声明类

getDeclaringClass()

Class对象

如果该类为内部类,则返回它的成员类,否则返回null


转载请注明本文地址: JAVA之Class类与反射总结

猜你喜欢

转载自blog.csdn.net/kkwant/article/details/80858402