java反射

如何获得Class类对象(三种方式):

  1. 通过Object提供的方法:public final Class<?> getClass();
  2. 利用“类.class”的方式实例化Class对象:如String.class;
  3. 利用Class类提供的方法(推荐),字符串参数要带上包名:public static Class<?> forName(String className) throws ClassNotFoundException

在一个JVM中,一种类,只会有一个类对象存在。所以以上三种方式取出来的类对象,都是一样的。


注: 准确的讲是一个ClassLoader下,一种类,只会有一个类对象存在。通常一个JVM下,只会有一个ClassLoader。因为还没有引入ClassLoader概念, 所以暂时不展开了。

示例:用三种方法实例化String的类对象比较 

public class Test {
    public static void main(String[] args) throws Exception  {

        String str="hello";

        Class c1=str.getClass();
        Class c2=String.class;
        Class c3=Class.forName("java.lang.String");

        System.out.println(c1==c2);
        System.out.println(c1==c3);

        System.out.println(c1);
    }
}

 运行结果:

true
true
class java.lang.String

 

通过反射代替new创建对象(两种方法)

1.Class类提供的方法:

当类没有无参构造时抛出InstantiationException,当类的无参构造时私有的时候抛出IllegalAccessException

 

2.Class类取得Constructor对象,再由Constructor创建对象:

 

通过反射的两种方法创建对象:

package test;

public class Test {
    public static void main(String[] args) throws Exception  {

        Class c=Class.forName("test.Person");
        //1.通过Class类对象直接创建Person对象
        Person p=(Person) c.newInstance();
        
        //2.通过Class构造Constructor对象,再创建Person对象
        Constructor constructor=c.getConstructor(String.class);
        Person p1=(Person)constructor.newInstance("xx");

        p.setName("hh");
        System.out.println(p.getName());
        System.out.println(p1.getName());
    }
}

public class Person {
    private String name;

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

 

运行结果:

hh
xx

说明一下,反射中的泛型设计的很差,所有的都是<?>,所以这里的泛型在反射中其实没什么意义。

 

通过反射机制完善工厂设计模式

首先来看一下传统工厂模式的代码:

interface Fruit{
    public void eat();
}
class Apple implements Fruit{
    public void eat(){
        System.out.println("吃苹果");
    }
}
class Orange implements Fruit{
    @Override
    public void eat() {
        System.out.println("吃橘子");
    }
}
class Factory{
    public static Fruit getInstance(String name){
        if (name.equals("apple")){
            return new Apple();
        }
        else if (name.equals("orange")){
            return new Orange();
        }
        else return null;
    }
}
public class TestFactory {
    public static void main(String[] args){
        Fruit fruit=Factory.getInstance("apple");
        fruit.eat();
    }

}

以上设计的缺陷是每当增加一个Fruit子类时,都要去修改Factory类的getInstance()方法。接下来我们可以利用反射来弥补这个缺憾:

package test;

interface Fruit{
    public void eat();
}
class Apple implements Fruit{
    public void eat(){
        System.out.println("吃苹果");
    }
}
class Orange implements Fruit{
    @Override
    public void eat() {
        System.out.println("吃橘子");
    }
}
class Factory{
    public static Fruit getInstance(String name) throws Exception {

            return (Fruit) Class.forName(name).newInstance();

    }
}
public class TestFactory {
    public static void main(String[] args) throws Exception {
        Fruit fruit=Factory.getInstance("test.Apple");
        fruit.eat();
    }

}

这样,就解决了工厂类的固化问题。当然,上面的代码还是有不足的地方,因为上面的设计要求客户端(也就是TestFactory类)准确的写出要操作的子类的具体名称(也就是test.Apple)。也就是说,如果客户端想要调用不同的子类方法,就需要修改程序代码,这样是不好的。解决方法可以新建一个配置文件,客户端通过修改配置文件属性来达到调用它想调用的方法的目的,而不用修改程序代码。

 

调用方法

1.首先通过Class对象获取Method方法:

Class类有两种方法获得Method:

(1)只能获取到在自己的类里面定义过的方法(包括private,protected),不能获取到它继承了但没有在自己类定义的方法:

(2)可以获取到所有的public方法,包括从父类(所有父类,包括自己定义的父类或是jdk中已定义过的父类,如Object)继承而来的。假如有一个方法子类重写了父类,那么子类的方法便覆盖父类的,只获取到子类的方法:

2.通过Method的invoke()调用方法:

public class Test {
    public static void main(String[] args) throws Exception  {

        Class c=Class.forName("test.APHero");

        //查看本类定义过的方法
        Method[] m1=c.getDeclaredMethods();
        for (int i=0;i<m1.length;i++){
            System.out.println(m1[i]);
        }
        System.out.println("**************");
        //查看本类定义的方法以及继承而来的方法(不包括父类中已被本类重写了的方法)
        Method[] m=c.getMethods();
        for (int i=0;i<m.length;i++){
            System.out.println(m[i]);
        }

        //调用magicAttack()
        Object o=c.newInstance();
        Method method=c.getMethod("magicAttack",String.class);
        method.invoke(o,"pp");
    }
}

public abstract class Hero {
    public String name;
    protected int number;
    private String title;

    @Override
    public String toString() {
        return "Hero [name=" + name + "]";
    }

    protected void attackHero(Hero h2) {
        System.out.println(this.name+ " 正在攻击 " + h2);
    }

    public void magicAttack(String name) {
        System.out.println("父亲进行魔法攻击"+name);
    }

}
public class APHero extends Hero {
    public String role;
    protected int id;
    private String pet;

    public void magicAttack(String name) {
        System.out.println("APHero进行魔法攻击"+name);
    }
    protected void fun(){
        System.out.println("protected方法");
    }
    private void gg(){
        System.out.println("private方法");
    }
}


运行结果:

public void test.APHero.magicAttack(java.lang.String)
private void test.APHero.gg()
protected void test.APHero.fun()
**************
public void test.APHero.magicAttack(java.lang.String)
public java.lang.String test.Hero.toString()
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
APHero进行魔法攻击----奥特曼

 

访问属性

1.首先通过Class对象获取Field对象:

同样有两种方式,第一种获取到本类中定义的所有属性(包括私有,保护的),第二种获取到本类中定义的和继承而来的所有公共属性:

2.通过Field对象设置和访问属性值:

(Hero类,APHero类和上面一样)

public class Test {
    public static void main(String[] args) throws Exception  {

        Class c=Class.forName("test.APHero");

        Field[] fields1=c.getDeclaredFields();
        for (int i=0;i<fields1.length;i++){
            System.out.println(fields1[i]);
        }
        System.out.println("*******************");

        Field[] fields2=c.getFields();
        for (int i=0;i<fields2.length;i++){
            System.out.println(fields2[i]);
        }

        Object o=c.newInstance();
        Field field=c.getDeclaredField("role");
        field.set(o,"术士");
        System.out.println(field.get(o));
        
    }
}

运行结果:

public java.lang.String test.APHero.role
protected int test.APHero.id
private java.lang.String test.APHero.pet
*******************
public java.lang.String test.APHero.role
public java.lang.String test.Hero.name
术士

 

设置访问权限——Accessible类

Constructor,Method,Accessible都继承了AccessibleObject类,而Accessible提供了访问权限相关的操作:

(Hero,APHero和上面一样)

public class Test {
    public static void main(String[] args) throws Exception  {

        Class c=Class.forName("test.APHero");

        Object o=c.newInstance();

        Method method=c.getDeclaredMethod("gg");
        method.setAccessible(true);//没有这一步会抛IllegalAccessException
        method.invoke(o);

        Field field=c.getDeclaredField("pet");
        field.setAccessible(true);//没有这一步会抛IllegalAccessException
        field.set(o,"火凤凰");
        System.out.println(field.get(o));
        
    }
}

运行结果:

private方法
火凤凰

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值