反射

反射

反射提供的功能:

  1. 在运行时判断任意一个对象所属的类
  2. 在运行时构造任意一个类的对象
  3. 在运行时判断任意一个类所具有的成员变量和方法
  4. 在运行时获取泛型信息
  5. 在运行时调用任意一个对象的成员变量和方法
  6. 在运行时处理注解
  7. 生成动态代理

java.lang.Class						代表一个类
java.lang.reflect.Constructor;		构造方法
java.lang.reflect.Field;			属性
java.lang.reflect.Method;			方法

利用反射创建对象

公有属性,方法,构造方法

Class<Person> cla = Person.class;

使用反射创建对象,利用公用构造器
Constructor<Person> con = cla.getConstructor(String.class , int.class , String.class);
Person pe = con.newInstance("猪八戒",20,"濮阳");			获得Person对象

调属性
Field name = cla.getDeclaredField("locatal");
name.set(pe,"漯河");
       
调方法
Method getname = cla.getDeclaredMethod("getName");
String myname = getname.invoke(pe);

私有属性,方法,构造方法

Class<Person> cla = Person.class;

构造方法
Constructor<Person> con2 = cla.getDeclaredConstructor();
con2.setAccessible(true);
Person pe2 = con2.newInstance();

属性
Field name = cla.getDeclaredField("name");
name.setAccessible(true);
name.set(pe2,"蔡文姬");

方法
Method setage = cla.getDeclaredMethod("setAge",int.class);
setage.setAccessible(true);
setage.invoke(pe2,18);

System.out.println(pe2.toString());

反射的用处

反射和封装是否矛盾?

​ 不矛盾。看起来好像是矛盾的

​ 封装性的用处是提示:不建议调用私有方法,调用公有方法就够用了

​ 反射解决的是能不能调的问题

创建对象用哪个?

1.  建议用new

 		2. 但是有时用反射,学习Java web时再解决

Class类的理解

内部解析

  1. .java文件经过javac.exe之后,会生成字节码文件.class文件,一个Java类对应一个.class文件。
  2. 然后使用java.exe对某个字节码文件解释运行,加载到内存中。
  3. 加载到内存中的类叫做运行时类,就是这个Class类。
  4. 换句话说:Class的实例对应着一个运行时类。
  5. 我们可以利用这个实现创建新的对象

加载到内存中的运行时类会缓存一定的时间,在此时间内,我们可以用不同方式获取运行时类,获取到的是同一个运行时类

哪些类型具有Class对象?

  • class
  • interface
  • [ ]数组:只要元素类型和维度一样,则是同一个Class
  • enum
  • annotation
  • 基本数据类型
  • void

获取Class实例的方式

一:直接属性获得

动态性比较差,当类名写错的时候,编译时就报错

Class<Person> cla = Person.class;

二:通过运行时的类获得

可以用来比较两个对象是不是由同一个类实例化的

 Person p1 = new Person();
 Class<? extends Person> cla2 = p1.getClass();

三:使用对象名获得

很常用,动态性强,既是类名写错编译时也不会报错

Class cla3 = Class.forName("test.Person");

四:使用类加载器获得

了解一下就行

下面一行的construct指的是当前代码所在的类名
ClassLoader loader = construct.class.getClassLoader();
Class cla4 = loader.loadClass("test.Person");

properties读取配置文件

首先创建一个jdbc.properties文件,和jdbc.properties,一个在modul下,一个在src下

里面的内容写键值对:

user=刘春阳
password=123456

方式一

默认搜索路径是当前module下,eclipse是在当前项目下

Properties pros = new Properties();

FileInputStream inp = new FileInputStream("jdbc.properties");
//可以读取src内的文件
FileInputStream inp1 = new FileInputStream("src\\jdbc1.properties");
pros.load(inp);

String str = pros.getProperty("user");
System.out.println(str);

方式二

默认搜索路径是src下

Properties pros = new Properties();

ClassLoader load = construct.class.getClassLoader();
InputStream imp = load.getResourceAsStream("jdbc.properties");
pros.load(imp);

String str = pros.getProperty("user");
System.out.println(str);

创建运行时类的对象

调用空参构造器

用的比较多,比较常用,但是要确保具有空参构造器

Class cla =  Class.forName("test.Person");
Person pe = (Person)cla.newInstance();

.newInstance():默认调用空参构造器,因此使用的时候必须确保具有空参构造器可被调用

调用带参构造器

用的比较少,因为写出来的代码只使用与这一个类,不通用。

Class cla =  Class.forName("test.Person");
Constructor<Person> cons = cla.getConstructor(String.class,int.class,String.class);
Person pe = cons.newInstance("后羿",20,"王者峡谷");

举例

外部调用这个函数,传进去对象的路径即可

public Object getInstance(String path) throws Exception{
    Class cla = Class.forName(path);
    return cla.newInstance();
}

获取运行时类的完整结构

了解即可,项目中基本不用这个

获取属性

获取运行时类及其父类内为public型的属性

Field[] fil = cla.getFields();
for(Field i : fil){
    System.out.println(i);
}

获取运行时内内部的所有属性,不包括其父类

Field[] fil2 = cla.getDeclaredFields();
for(Field i : fil2){
   System.out.println(i);
}

获取类内部某个属性的指定信息

只是在上面for循环的基础上再调用属性

Field[] fil2 = cla.getDeclaredFields();
for(Field i : fil2){
    //获取权限修饰符,返回值为int,需要用toString转换为对应值
    int fir = i.getModifiers();
    System.out.print(Modifier.toString(fir)+"  ");
    //获取数据类型,返回的是Class
    Class ty = i.getType();
    System.out.print(ty+"  ");
    //获取变量名
    System.out.println(i.getName());
}

获取方法

前两步与上面的获取属性一样,将Field变成Method即可

Class cla = Person.class;
Method[] met = cla.getDeclaredMethods();
for(Method i : met)
获取方法的注解
Annotation[] ann = i.getAnnotations();
	for(Annotation w : ann)
	System.out.println(w);
获取方法权限修饰符
i.getModifiers()		返回的事int型数值,需要用下面的函数进行转换
Modifier.toString()
获取方法返回值
i.getReturnType()
获取方法名
i.getName()
形参方法参数列表

返回的是Class数组

Class[] qwe = i.getParameterTypes();
	for(Class w : qwe)
		System.out.println(w);
返回抛的异常

也是一个Class数组

Class[] exce = i.getExceptionTypes();
	for(Class w : exce)
		System.out.println(w);

获取构造方法

获取public修饰的构造器
Constructor[] con = cla.getConstructors();
获取所有的构造器
Constructor[] coms = cla.getDeclaredConstructors();

获取父类

Class cl = cla.getSuperclass();
System.out.println(cl);

获取父类及其泛型

Type cl = cla.getGenericSuperclass();		返回值为Type类型
System.out.println(cl);

仅获取父类的泛型

Type cl = cla.getGenericSuperclass();
ParameterizedType para = (ParameterizedType) cl;
Type[] tya = para.getActualTypeArguments();
for(Type w : tya)
	System.out.println(w);

获取接口

Class[] c = cla.getInterfaces();
	for(Class w : c)
        System.out.println(w);

获取所在的包

Class cla = Person.class;
    Package pac = cla.getPackage();
        System.out.println(pac);

获取类的注解

Annotation[] a = cla.getAnnotations();

调用运行时类的指定结构

属性

Class cla = Person.class;
Person pe = (Person)cla.newInstance();

 //可以获取一个类的所有格式属性
Field fi = cla.getDeclaredField("name");
//使私有的变量可以用反射进行修改
fi.setAccessible(true);
fi.set(pe,"你好");
System.out.println(fi.get(pe));


下面这个函数只能获取public修饰个属性,所以说不经常用
//获取指定的属性,只能获取public的
Field fi = cla.getField("locatal");
//给某个对象的某个属性赋值
fi.set(pe,"nihao");
System.out.println(fi.get(pe));
System.out.println(pe.toString());

方法

静态方法

静态属性同理,使用任意一个对象调用赋值即可

Class<Person> cla = Person.class;
Person pe = cla.newInstance();
//获取所有权限的方法
Method mttt = cla.getDeclaredMethod("sayhellow");
mttt.setAccessible(true);
String str = (String) mttt.invoke(PerSon.class);括号内也可以设置null,随意一个就行,因为是静态方法
System.out.println(str);

动态方法

//第一个参数指明函数名,后面的参数值函数内的形参类型
Method mea = cla.getDeclaredMethod("setAge",int.class);
mea.setAccessible(true);
//参数1:指定的对象,后面的参数:实参值.方法有返回值,object类型
mea.invoke(pe,19);
System.out.println(pe.getAge());

构造器

一般就是使用class对象直接newInstance()造对象,调用非空构造器不常用

Constructor<Person> con2 = cla.getDeclaredConstructor(String.class , int.class , String.class);
con2.setAccessible(true);
Person pe2 = con2.newInstance("猪八戒",20,"濮阳");

代理模式

静态代理

很简洁明了,但是就是不懂有何用

package ha;

//一个接口,很重要
interface Netwotk{
    void browse();
}

//被代理类
class Server implements Netwotk{

    @Override
    public void browse() {
        System.out.println("真实的服务器访问网络");
    }
}

//代理类
class ProxyServer implements Netwotk{
    private Netwotk work;
	//将主函数内的Netwotk对象传进来
    public ProxyServer(Netwotk work){
        this.work = work;
    }
	//未知的一些操作,按需所写
    public void check(){
        System.out.println("联网前的一些操作");
    }
    @Override
    public void browse() {
        check();
        work.browse();		//调用被代理类内的相关函数
    }
}

//主函数
public class staticProxy {
    public static void main(String[] args) {
        Server se = new Server();
        ProxyServer pro = new ProxyServer(se);
        pro.browse();
    }
}

动态代理

扩展性比静态代理好

package ha;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface human{
    String getBelief();
    void eat(String food);
}

//被代理类
class SuperMan implements human{

    @Override
    public String getBelief() {
        return "I am ironman";
    }

    @Override
    public void eat(String food) {
        System.out.println("我喜欢吃:"+food);
    }
}
//动态生成被代理类
class ProxyFactory{
    //调用此方法,返回代理类的对象
    public static Object getProxyInstance(Object obj){ //obj是被代理类对象
        MyInvocationHandler hande = new MyInvocationHandler();
        hande.bind(obj);
        return Proxy.newProxyInstance(obj.getClass().getClassLoader()
                ,obj.getClass().getInterfaces()
                ,hande);
    }
}
//需要继承指定的接口
class MyInvocationHandler implements InvocationHandler{
    private Object obj; //赋值时需要被代理类对象进行赋值

    public void bind(Object obj){
        this.obj = obj;
    }
    //当我们通过代理类的对象,调用方法a时,就会自动调用下面的方法
    //将被代理类要执行的方法a的功能就声明在invoke()中
    @Override           //被代理对象        要调用的函数    函数内的参数
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object valuess = method.invoke(obj,args);       //函数的返回值
        return valuess;
    }
}

public class ProxyTest {
    public static void main(String[] args) {
        SuperMan man = new SuperMan();
        //代理类对象,此时就不仅仅局限于human了,上面写的方法是通用的,被代理类可以随意的换成其他的
        human proxyInstance = (human) ProxyFactory.getProxyInstance(man);
        proxyInstance.eat("王婆大虾");
        String str = proxyInstance.getBelief();
        System.out.println(str);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值