java反射以及代码实现

Java反射面试

在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个属性和方法。依靠此机制,可以动态的创建一个类的对象和调用对象的方法。

其次就是反射相关的API,只讲一些常用的,比如获取一个Class对象。Class.forName(完整类名)。通过Class对象获取类的构造方法,class.getConstructor。根据class对象获取类的方法,getMethod和getMethods。使用class对象创建一个对象,class.newInstance等。

最后可以说一下反射的优点和缺点,优点就是增加灵活性,可以在运行时动态获取对象实例。缺点是反射的效率很低,而且会破坏封装,通过反射可以访问类的私有方法,不安全。

如果了解JVM可以结合JVM的相关知识说。

  • 反射可以在程序运行期间加载、探知和使用编译期间完全未知的类。

获取Class类的实例

public class Test02 {
    public static void main(String[] args) throws ClassNotFoundException {
        Person person =new Student();
        System.out.println("这个人是:"+person.name);
        //方式一:通过对象获取
        Class c1=person.getClass();
        //方式二:forname获取
        Class c2=Class.forName("Student");
        System.out.println(c2.hashCode());
        //方式三:通过.class获得
        Class c3 = Student.class;
        System.out.println(c3.hashCode());
        //方式四:基本内置类型的包装类都有一个Type属性
        Class c4=Integer.TYPE;
        System.out.println(c4);
        //获得父类类型
        Class c5=c1.getSuperclass();
        System.out.println(c5);
    }
}
class Person{
   public String name;
    public Person(){
    }

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

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}
class Student extends Person{
    public Student(){
        this.name="学生";

    }
}
class Teacher extends Person{
    public Teacher(){
        this.name="老师";

    }
}

那些类可以有Class对象?

class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类。
interface:接口
[]:数组
enum:枚举
annotation:注解@interface
primitive type:基本数据类型
void

public class Test03 {
    public static void main(String[] args) {
        Class c1=Object.class;//类
        Class c2=Comparable.class;//接口
        Class c3=String[].class;//一维数组
        Class c4=int[][].class;//二位数组
        Class c5=Override.class;//注解
        Class c6= ElementType.class;//枚举
        Class c7=Integer.class;//基本数据类型
        Class c8=void.class;//void
        Class c9=Class.class;//Class
        //快速换行复制ctrl+D
        //多行选择复制alt
        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c3);
        System.out.println(c4);
        System.out.println(c5);
        System.out.println(c6);
        System.out.println(c7);
        System.out.println(c8);
        System.out.println(c9);
        //只要元素类型与维度(一维数组跟多维数组)一样,就是同一个Class.
        int[] a=new int[10];
        int[] b=new int[100];
        System.out.println(a.getClass().hashCode());
        System.out.println(b.getClass().hashCode());
    }
}

Java内存分析

在这里插入图片描述

类加载器

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

public static void main(String[] args) throws ClassNotFoundException {
        //获取系统类的加载器
        ClassLoader systemClassLoader=ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);
        //获取系统类加载器的父类加载器-->扩展类加载器
        ClassLoader parent =systemClassLoader.getParent();
        System.out.println(parent);
        //获取扩展类加载器的父类加载器-->根加载器(c/c++)
        ClassLoader parent1 = parent.getParent();
        System.out.println(parent1);
        //测试当前类是那个加载器加载的
        ClassLoader classLoader=Class.forName("Test04").getClassLoader();
        System.out.println(classLoader);
        //测试JDK内置的类是那个加载器加载的
        classLoader=Class.forName("java.lang.Object").getClassLoader();
        System.out.println(classLoader);
        //如何获得系统类加载器可以加载的路径
        System.out.println(System.getProperty("java.class.path"));

    }

获取运行时类的完整结构

Field、Method、Constructor、Superclass、Interface、Annotation

public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class c1=Class.forName("User");
        User user = new User();
        c1=user.getClass();
        //获得类的名字
        System.out.println(c1.getName());//获取包名+类名
        System.out.println(c1.getSimpleName());//获得类名
        //获得类的属性
        Field[] fields=c1.getFields();//只能找到public属性
        fields=c1.getDeclaredFields();//找到全部的属性
        for(Field field:fields){
            System.out.println(field);
        }
        //获得指定属性的值
        Field name =c1.getDeclaredField("name");
        System.out.println(name);
        System.out.println("***********************");
        //获得类的方法
        Method[] methods = c1.getMethods();//获得本类及其父类的全部public方法
        for(Method method:methods){
            System.out.println("正常的:"+method);
        }
        methods=c1.getDeclaredMethods();//获得本类的所有方法
        for(Method method:methods){
            System.out.println("getDeclaredMethods:"+method);
        }
        //获得指定方法
        //重载
        Method getName=c1.getMethod("getName",null);
        Method setName=c1.getMethod("setName",String.class);
        //Method setName=c1.getMethod("getName",String.class);
        System.out.println(getName);
        System.out.println(setName);

        //获得指定的构造器
        System.out.println("***********************");
        Constructor[] constructors = c1.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
        Constructor[] declaredConstructors = c1.getDeclaredConstructors();
        for (Constructor declaredConstructor : declaredConstructors) {
            System.out.println("#"+declaredConstructor);

        }
        //获得指定的构造器
        Constructor declaredConstructor=c1.getDeclaredConstructor(String.class,int.class,int.class);
        System.out.println("指定:"+declaredConstructor);

    }

有了Class对象,能做什么?

 public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //获得class对象
        Class c1=Class.forName("User");
        //构造一个对象
        User user  = (User) c1.newInstance();//本质是调用的无参构造器
        System.out.println(user);

        //通过构造器创建对象
        Constructor declaredConstrcutor=c1.getDeclaredConstructor(String.class,int.class,int.class);

        User user2=(User) declaredConstrcutor.newInstance("张苏杭",001,18);
        System.out.println(user2);
        //通过反射调用普通方法
        User user3=(User)c1.newInstance();//通过反射创建一个对象
        //通过反射获取一个方法
        Method setName=c1.getDeclaredMethod("setName", String.class);
        setName.invoke(user3,"苏杭");//激活invoke(对象,"方法的值")
        System.out.println(user3.getName());
        //通过反射操作属性
        User user4=(User)c1.newInstance();
        Field name=c1.getDeclaredField("name");
        //不能直接操作私有属性,我们需要关闭程序的安全检测,属性或者方法的name.setAccessible(true)
        name.setAccessible(true);//
        name.set(user4,"书行");
        System.out.println(user4.getName());

    }

反射操作注解

要求:
在这里插入图片描述
代码:

import java.lang.annotation.*;
import java.lang.reflect.Field;
//练习反射操作注解
public class Test07 {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c1=Class.forName("Student2");
        //通过反射获取注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
        //获得注解的value的值。
        Tablesu annotation1=(Tablesu)c1.getAnnotation(Tablesu.class);
        String value = annotation1.value();
        System.out.println(value);
        //获得类指定的注解
        Field f=c1.getDeclaredField("name");
        Fieldsu annotation=f.getAnnotation(Fieldsu.class);
        System.out.println(annotation.columnName());
        System.out.println(annotation.type());
        System.out.println(annotation.length());
    }

}
@Tablesu("db_student")
class Student2{
    @Fieldsu(columnName= "db_id",type = "int",length = 10)
    private int id;
    @Fieldsu(columnName= "db_age",type = "int",length = 10)
    private int age;
    @Fieldsu(columnName= "db_name",type = "varchar",length = 10)
    private String name;

    public Student2() {
    }

    public Student2(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Student2{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}
//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Tablesu{
    String value();
}
//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Fieldsu{
    String columnName();
    String type();
    int length();
}

反射使用的场景

  • JDBC中,利用反射动态加载了数据库驱动程序。
  • Web服务器中利用反射调用了Sevlet的服务方法。
  • 很多框架都用到反射机制,注入属性,调用方法,如Spring。

什么叫对象序列化,什么是反序列化,实现对象序列化需要做那些工作?

对象序列化,将对象中的数据编码为字节序列的过程。

反序列化;将对象的编码字节重新反向解码为对象的过程。

JAVA提供了API实现了对象的序列化和反序列化的功能,使用这些API时需要遵守如下约定:

被序列化的对象类型需要实现序列化接口,此接口是标志接口,没有声明任何的抽象方法,JAVA编译器识别这个接口,自动的为这个类添加序列化和反序列化方法。

为了保持序列化过程的稳定,建议在类中添加序列化版本号。

不想让字段放在硬盘上就加transient

以下情况需要使用Java序列化:

想把的内存中的对象状态保存到一个文件中或者数据库中时候;

想用套接字在网络上传送对象的时候;

想通过RMI(远程方法调用)传输对象的时候。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值