反射

本文详细介绍了Java中获取类对象的三种方式、反射操作类对象的方法、工厂模式、单例模式的实现及其问题,以及枚举和注解的使用。
摘要由CSDN通过智能技术生成

在这里插入图片描述

比较重要的点:

获取类对象的三种方式**

1 类名.class 2 对象.getClass() 3 Class.forName(str)

类对象常用的方法 newInstance() 获取某个类的对象(调用某个类的空参构造方法)

     类      Class          Class.forName()     .newInstance()
    属性     Field          set(obj,value)           get()
   构造方法   Constructor    newInstance()
    方法     Method         invoke(obj,value)
    参数     Parameter      getType() 参数类型

工厂模式:通过工厂类产生对象,利用反射动态产生对象

单例模式: (1)构造方法私有化 (2)提供一个公有的方法,返回实例

饿汉式:类加载时实例就会被创建,优点是线程安全,缺点资源浪费

懒汉式:调用时方法时,实例才会创建,优点节约资源,缺点线程不安全 ( DCL(双重检测锁) + volatile 或 静态内部类 )

枚举:本质上是终态类,属性本质上当前类型的静态常量

注解: 元注解@Target 作用范围 TYPE 类、FIELD 属性、 METHOD 方法、PARAMETER 参数

​ @Retention 生命周期 RUNTIME 运行阶段有效

类对象

类对象:类加载的产物,封装了一个类的所有信息(类名、父类、接口、属性、方法、构造方法) 。
注意:每个类加载到内存都会生成一个唯一的类对象。
获取类对象的三种方式
1、通过对象的getClass方法
2、通过类的class属性
3、通过Class类的forName方法

public static  void test01(){
    //1、通过对象的getClass方法
    //Student stu = new Student();
    //Class c = stu.getClass();
    //class com.qf.reflect.Student  全的限定名(包名+类名)
    //System.out.println(c);

    //2、通过类的class属性
    //Class c = Student.class;
    //class com.qf.reflect.Student
    //System.out.println(c);

    //3、通过Class类的forName方法  参数:全限定名  (此方法的作用:1、触发类加载 2、获取类对象)
    try {
        Class c = Class.forName("com.qf.reflect.Student");
        System.out.println(c);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

Filed类

Field类表示类对象中的属性
获取它的目的:赋值和取值

public static void test04(){
    try {
        //1、获取类对象
        Class c = Class.forName("com.qf.reflect.Student");
        Object o = c.newInstance();//确保1、无参构造2、public修饰
        //获取指定公开的属性
        //Field field = c.getField("money");        
        //对属性进行赋值
        //field.set(o,200.55);
        //获取属性中的值
        //System.out.println(field.get(o));
        
        //获取所有公开的属性(包括父类的)
        //Field[] fields = c.getFields();
        //System.out.println(Arrays.toString(fields));

        //获取执行的私有属性
        //Field field = c.getDeclaredField("name");
        //暴力反射
        //field.setAccessible(true);
        //field.set(o,"张三");
        //System.out.println(field.get(o));
        
        //获取所有的属性(包括私有的)
        Field[] fields = c.getDeclaredFields();
        System.out.println(Arrays.toString(fields));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Constructor类

Constructor类表示类对象中的方法
获取它的目的,创建对象

public static void test03(){
    try {
        //1、获取类对象
        Class c = Class.forName("com.qf.reflect.Student");
        //获取这个类的指定的构造方法
        //Constructor constructor = c.getConstructor(String.class, int.class);
        //通过构造方法new对象
        //Object stu = constructor.newInstance("张三",30);
        //System.out.println(stu);
        
        //获取所有公开的构造方法
        // onstructor[] constructors = c.getConstructors();
        //System.out.println(Arrays.toString(constructors));
        
        //获取所有的构造方法(包括私有的)
        //Constructor[] constructors = c.getDeclaredConstructors();
        //System.out.println(Arrays.toString(constructors));
        
        //获取指定私有的无参构造方法
        Constructor constructor = c.getDeclaredConstructor();
        //设置私有可以访问(暴力反射)
        constructor.setAccessible(true);
        Object o = constructor.newInstance();
        System.out.println(o);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Method类

Method类表示类对象的方法
获取它的目的,调用它并获取方法的返回值(如果方法没有返回值则返回null)

public static void test05(){
    try {
        //1、获取类对象
        Class c = Class.forName("com.qf.reflect.Student");
        Object o = c.newInstance();
        //获取指定公开的方法
        //Method method = c.getMethod("show", String.class);       
        //利用反射调用方法,并接收返回值
        //Object result = method.invoke(o, "wuwu,网比较卡");
        //System.out.println(result);


        //获取所有的公开的方法(包括父类的公开的方法)
        //Method[] methods = c.getMethods();
        //System.out.println(Arrays.toString(methods));
        
        //获取指定的私有方法
        //Method method = c.getDeclaredMethod("print");
        //method.setAccessible(true);
        //利用反射调用方法,并接收返回值(如果方法没有返回值。那么invoke方法就返回null)
        //Object result = method.invoke(o);
        //System.out.println(result);

        //获取本类中所有的方法(包括私有的)
        Method[] methods = c.getDeclaredMethods();
        System.out.println(Arrays.toString(methods));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

工厂模式

开发中有一个非常重要的原则“开闭原则”,对拓展开放、对修改关闭。
工厂模式主要负责对象创建的问题。
可通过反射进行工厂模式的设计,完成动态的对象创建。

//Phone接口
public interface Phone {
    public void call();
    public void recive();
}
//手机类
public class HuaWeiPhone implements Phone{
    @Override
    public void call() {
        System.out.println("华为手机打电话");
    }

    @Override
    public void recive() {
        System.out.println("华为手机接电话");
    }
}
public class XiaoMiPhone implements Phone{
    @Override
    public void call() {
        System.out.println("小米手机打电话");
    }

    @Override
    public void recive() {
        System.out.println("小米手机接电话");
    }
}
//利用反射创建对象
public class PhoneFactory {
    /**
     * 利用反射,创建工厂类创建对象
     * @param className
     * @return
     */
    public static Phone getPhoneRef(String className){
        try {
            Class<?> pClass = Class.forName(className);
            Phone phone = (Phone) pClass.newInstance();
            return phone;

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return null;

    }

    public static void main(String[] args) {
        Phone xmPhone = PhoneFactory.getPhoneRef("com.qf.factory.XiaoMiPhone");
        xmPhone.call();
        xmPhone.recive();
        Phone hwPhone = PhoneFactory.getPhoneRef("com.qf.factory.HuaWeiPhone");
        hwPhone.call();
        hwPhone.recive();
    }
}

//bean.properties文件建在src下边,格式:key=value
//有一个接口,具体类实现接口,利用接口创建具体类对象
public class BeanFactory {
    private static Map<String,Object> map=new HashMap<String,Object>();
    static {

        try {
            Properties properties = new Properties();
            //读取src下的properties文件
            properties.load(BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties"));
            //读取文件的key值集合
            Set<Object> set = properties.keySet();
            for (Object s:set){
                //获取类对象
                Class<?> pClass = Class.forName((String) properties.get(s));
                //创建对象
                Object v = pClass.newInstance();
                //将key和创建的对象加到map
                map.put((String) s,v);
            }



        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }


    }

    public static Phone getPhoneBean(String name){
        return (Phone) map.get(name);
    }
}

单例模式

让类的对象只能有唯一的一个实例
单例分类:
懒汉式

  • 好处:避免资源浪费(需要对象的时候就创建对象)
  • 缺点 :线程不安全
  • 解决:
    • 1、DCL(双重检测锁) +volatile
      • DCL的问题:
      • 解决:volatile关键字修饰 1、避免指令重排 2、多线程可见性
    • 2、使用静态内部类(什么时候使用静态内部类,什么时候就加载)
      饿汉式
  • 好处:线程安全。
  • 缺点:浪费资源。只要类被加载,那么这个类实例就会被创建
    如何实现单例
  • 1、私有化构造方法
  • 2、提供一个方法,返回这个类的实例
    反射破坏单例的问题:
    解决:在构造方法中加上判断,如果对象不为空则直接抛出异常

饿汉式

public class Singleton01 {
    private static Singleton01 singleton01 = new Singleton01();

    private Singleton01(){
    }
    public static Singleton01 getInstance(){
        return singleton01;
    }
}

懒汉式(DCL解决)

public class Singleton02 {
    private static volatile Singleton02 singleton02; //volatile
    private Singleton02(){  
    }
    public static Singleton02 getInstance(){
        //双重检验锁  DCL(double check lock) 1、指令重排  2、可见性(在多线程间可见)
        if(singleton02 == null){
            synchronized (Singleton02.class){//互斥锁标记
                if(singleton02 == null){
                    //java中允许指令重排序

                    singleton02 =  new Singleton02();
                }
            }
        }
        return singleton02;
    }
}

懒汉式单例(静态内部类)

public class Singleton03 {
    private Singleton03(){}

    public static Singleton03 getInstance(){
        return Holder.singleton03;
    }

    //静态内部类(什么时候使用静态内部类,什么时候就加载)
    public static class Holder{
        private static Singleton03 singleton03 = new Singleton03();
    }

}

反射破坏单例(任何单例都会遭到反射的破坏,因为反射可以直接执行私有的构造方法)

private static volatile Singleton02 singleton02; 
private static Object obj = new Object();
private Singleton02(){
    if(singleton02 != null){
        throw new IllegalArgumentException("不要试图使用反射破坏单例");
    }
}

枚举

枚举是一个引用类型,枚举是一个规定了取值范围的数据类型。
一般已经确定类的对象个数,可以使用枚举定义
枚举变量不能使用其他的数据,只能使用枚举中常量赋值,提高程序安全性。
定义枚举使用enum关键字。
枚举的本质:
枚举是一个终态类,并继承Enum抽象类。
枚举中常量是当前类型的静态常量。

public enum Color {
    //枚举类的三个实例
    RED,GREEN,YELLOW;
    //可以定义属性、方法
    private String name;
    public void show(){
        System.out.println("show...");
    }
    //定义构造方法(必须私有)
    private Color(){}
    private Color(String title){
    }
}

注意:
枚举中必须要包含枚举常量,也可以包含属性、方法、私有构造方法。
枚举常量必须在前面,多个常量之间使用逗号隔开,如果没有定义其他内容,最后分号可写可不写。

注解

注解(Annotation):是代码里的特殊标记, 程序可以读取注解,一般用于替代配置文件。
定义注解使用@interface关键字,注解中只能包含属性。
常见注解:@Override

注解注意事项

  • 1、注解中只能是属性 ,本质上是抽象方法
  • 2、如果注解中属性只有一个必填注解,且是value。那么使用的时候,value=可以省略
  • 3、如果属性有默认值,那么在使用的时候可以不填
  • 4、如果属性是一个数组,那么在使用的时候如果只有一个参数,大括号可以省略
    元注解
    加在注解上的注解
    @Retention:定义注解的使用范围
  • Class (默认的) class源文件期间保留
  • Source 编译期间保留
  • Runtime 在运行期保留

@Target: 定义注解的使用范围

  • TYPE, 类上使用
  • FIELD, 属性上使用
  • METHOD, 方法上使用
  • PARAMETER, 参数上使用

注解的示例

//注解定义
//只能用在类上
@Target(ElementType.TYPE)
//运行时生效
@Retention(RetentionPolicy.RUNTIME)
public @interface TableName {
    String  name();
}
//注解的应用
@TableName(name = "tb_user")
public class User {
}

@TableName(name = "tb_man")
public class Man {
}

//使用
public class Test1 {
    public static String getsql(String name) throws ClassNotFoundException {
        Class<?> aClass = Class.forName(name);
        TableName annotation = aClass.getAnnotation(TableName.class);
        String s = annotation.name();
        return "select * from "+s;

    }

    public static void main(String[] args) throws ClassNotFoundException {
        System.out.println(getsql("com.qf.demo.User"));
        System.out.println(getsql("com.qf.demo.Man"));

    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值