1.反射
1)反射的定义:
Java中的反射,是指在运行过程中,对于任意的一个类,都可以知道这个类的所有属性和方法;对于任意一个对象,都可以调用它的任意的一个方法和属性,那么既然可以拿到,我们就可以修改部分类型信息;这种动态获取信息以及动态调用对象的方法的功能称之为Java语言的反射机制
所有有关于反射相关的类和相关的包都在java.lang.reflect包下面
2)反射中涉及到的一些常见的类(背)
反射中在哪里用到,介绍一下(面试--框架)
1)Class类:代表类的实体,在运行的java程序中表示类和接口
2)Field类:代表类的成员变量/类的属性
3)Method类:代表类的方法
4)Constructor类,它是代表类的构造方法
Java被编译之后,生成了.class文件,此时JVM就会要去解读.class文件,被编译后的java文件.class最终也被JVM解析成一个类,这个对象就是java.lang.Class当程序在运行的时候,每一个类就变成了Class对象的一个实例。这样当程序正在运行的时候我们通过java的反射机制应用到这个实例,就可以去获得甚至去改变这个类的属性和动作,是这个类称为一个动态的类;
class Student{
public int age=18;
private String name="bit";
public Student()
{
System.out.println("我是这个类中的不带有参数的构造方法");
}
private Student(String name,int age)
{
this.name=name;
this.age=age;
System.out.println("我是这个类中一个私有的构造方法");
}
public void start(String str)
{
System.out.println("我是这个类中的带参数的普通方法");
}
private void run()
{
System.out.println("我是这个类中的不带有参数的私有方法");
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
1)获取当前的Class对象(通过反射来获取类对象),此时有三种方式
1)通过Class.forName(里面是路径)方法
Class<?> C1=Class.forName("Student");//报名.类名 Class<?> C2= Student.class; Student student=new Student(); Class<?> C3=student.getClass(); System.out.println(C1==C2); System.out.println(C2==C3);不管是用哪种方式来获取Class对象,这里面的打印结果都是false,说明类对象只有一个2)通过类名.Class返回一个实例
3)先类创建实例,再通过引用.getClass()来进行返回
扫描二维码关注公众号,回复: 14334199 查看本文章![]()
2.创建对象
类对象的引用.newInstance()
Class<?> C1=Class.forName("Student"); Student lijiawei= (Student) C1.newInstance();//最重要进行强制类型转换,这样就可以实例化一个对象 System.out.println(lijiawei);
3.获取类中的构造器的方法
1)getConstructor(Class......<?> parameterTypes)获得该类中与参数类型相匹配的公有的构造方法
2)getConstructors()获取该类的所有的共有的构造方法
3)getDeclaredConstructor(Class<?> parameterTypes)获取该类中与参数类型相匹配的构造方法//即可以获取到公有,也可以获取到私有,如果在其中获取到了私有的构造方法,我们还是需要调用一下构造器引用.setAccessible()方法,将里面的参数设置成true
4)getDeclaredConstructors() 获取该类的所有构造方法
//先获取到类对象
Class<?> S1=Class.forName("Student"); //获取到构造器的引用 Constructor<Student> constructor= (Constructor<Student>) //接下来进行传参S1.getDeclaredConstructor(String.class,int.class); //调用构造方法为私有的时候才会设置这个参数constructor.setAccessible(true); //创建一个新的对象Student student= constructor.newInstance("lijiaxin",13); System.out.println(student);
4.反射私有的属性(获取私有的,获取公开的)
1)getField(String name) 获得某一个共有的属性对象
2)getFields()获取到所有的共有的属性对象
3)getDeclaredField(String name)获取到某一个属性对象,返回值是一个Field对象
4)getDeclaredFields()获取到所有的属性对象
//1获取到Class对象 Class<?> C1=Class.forName("Student"); //2获取到一个对象 //可以直接通过类对象的引用.newInstance来新创建一个对象 Student student= (Student) C1.newInstance(); //可以直接通过构造器来进行生成一个对象 Field field= C1.getDeclaredField("name"); field.setAccessible(true); //改变私有的属性字段 field.set(student,"张三"); System.out.println(student);
5.反射类中的方法
1)获取某个类中共有的方法:getMethod(),里面的参数是方法名,参数类型,class 2)获取到该类中所有的方法:getMethods() 3)获取到该类中的某一个方法getDeclaredMethod(String name,Class....<?> parameterTypes) 4)获取到该类中的所有方法:getDeclaredMethods(); Class<Student> studentClass= (Class<Student>) Class.forName("Student"); Student student=studentClass.newInstance(); Method method1= studentClass.getDeclaredMethod("run"); Method method2= studentClass.getMethod("start",String.class); method1.setAccessible(true); method2.invoke(student,"我是私有的run方法");我是这个类中的不带有参数的构造方法
我是这个类中的带参数的普通方法
我是私有的run方法
2.枚举
1)背景以及定义:
枚举是在JDK1.5之后进行引入的,目的用途是将一组常量组织起来,在这之前通常使用定义常量的方式例如:
public static final int RED=1;
public static final int GREEN=2;
public static final int BLACK=3;
但常量枚举有一个不好的地方,例如假设现在正好有一个数字,但是他可能会被误认为是RED,现在我们可以直接使用枚举来进行组织,这样一来就拥有了枚举类型而不是一个普通的数字1;
public enum TestEnum{
RED,BLACK,GREEN;
public static void main(String[] args]{
System.out.println(TestEnum.RED);//在类外要通过类名.的方式
System.out.println(BLACK);
}
}
此时打印出来的值就是RED,BLACK
public enum TestEnum{
RED,BLACK,GREEN;
public static void main(String[] args){
TestEnum testEnum=TestEnum.BLACK;
switch (testEnum){
case RED:
System.out.println("red");
break;
case BLACK:
System.out.println("black");
break;
case GREEN:
System.out.println("green");
break;
}
}
}
2.Enum中的常见方法(自己写的枚举类,默认继承了一个抽象类,public abstract class<E extends Enum<E>> implements Comparable<E>,Serializable;
1)values()以数组的形式返回枚举类型的所有成员
2)ordinal()获取到枚举成员的索引位置
3)valueOf()将普通字符串转化成枚举实例
4)compareTo()比较两个枚举成员定义的顺序,默认是通过索引来进行比较的
public enum TestEnum{
RED,BLACK,GREEN,WHITE;
public static void main(String[] args) {
TestEnum[] arr1=TestEnum.values();
for(int i=0;i< arr1.length;i++)
{
System.out.println(arr1[i]);
}
//把字符串变成对应的枚举对象
TestEnum testEnum= TestEnum.valueOf("RED");
System.out.println(testEnum);
System.out.println(RED.compareTo(BLACK));
System.out.println(BLACK.compareTo(WHITE));
}
}
1) 枚举的构造方法默认是私有的
2)枚举类是不可以被继承的
public enum TestEnum{ RED("hello",1),BLACK("world",2),GREEN("l want",3),WHITE("kkkk",4); public String color; public int origin; private TestEnum(String color,int origin)//此时的自己构造方法默认是私有的 {//super() this.color=color; this.origin=origin; }1)既然枚举的构造方法是私有的,那么我们是否可以通过反射来获取枚举对象的实例呢?
public enum TestEnum{ RED("hello",1),BLACK("world",2),GREEN("l want",3),WHITE("kkkk",4); public String color; public int origin; private TestEnum(String color,int origin)//此时的自己构造方法默认是私有的 { this.color=color; this.origin=origin; } public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { Class<Enum> S1= (Class<Enum>) Class.forName("TestEnum"); Constructor<Enum> constructor=S1.getDeclaredConstructor(String.class,int.class); //枚举的构造方法是私有的,所以要把参数设置成true constructor.setAccessible(true); TestEnum testEnum= (TestEnum) constructor.newInstance("BLUE",23); //构造方法里面再写"hhh",89;那么这时还是会报错的 System.out.println("枚举对象是"+testEnum); } } 这段代码时会报错的,他的报错的意思是没有这样的构造方法,但是在我们所写的代码中,是存在这样的构造方法的,那怎么会没有呢?原因是我们自己所写的枚举类默认是继承于上面的一个抽象类的,而这个抽象类的构造方式是含有两个参数的,所以在我们自己所写的枚举类型中,我们应该先要帮助父类进行构造
// TestEnum testEnum= (TestEnum) constructor.newInstance("BLUE",23);
构造方法里面再写"hhh",89;那么这时还是会报错的
在newInstance方法里面会进行判断,如果是枚举类型,是不可以创建实例的
所以我们进行总结,枚举类型是非常安全的,我们无法通过反射来进行获取到枚举类型的实例对象
2)如何设置一个线程安全的单例模式呢?
把构造方法设置成私有的,在类里面之创建一个实例,并进行返回;通过公开方法来获取到一个实例;
1)设计饿汉模式和懒汉模式,里面的字段属性一定要是private static 防止在类外被访问到,除了获取实例的方法之外设置成public之外;
public class Singleton { Object object = new Object(); private Singleton() { }; private volatile static Singleton singleton = null; public static Singleton getInstance() { if (singleton == null) { synchronized (Object.class) { if (singleton == null) { return new Singleton(); } } } return singleton; }class Singleton{ private Singleton(){}; private static final Singleton singleton=new Singleton(); public static Singleton getInstance() { return singleton; } }2)通过静态内部类来实现一个单例模式
class Singleton{ private Singleton(){}; private static class User{ private static final Singleton singleton=new Singleton(); } public static Singleton getInstance(){ return User.singleton; } } class TestEnum{ public static void main(String[] args) { Singleton singleton=Singleton.getInstance(); Singleton singleton1=Singleton.getInstance(); System.out.println(singleton1==singleton); } }3)通过枚举来实现一个单例模式
public enum TestEnum{ RED; public static TestEnum getInstance() { return RED; } public static void main(String[] args) { TestEnum testEnum1=TestEnum.getInstance(); TestEnum testEnum=TestEnum.getInstance(); System.out.println(testEnum==testEnum1); } }