IOC概念 和 反射(泛型、注解)

概念
IOC是Inversion of Control的缩写,多数书籍翻译成“控制反转”。

由于引进了中间位置的“第三方”,也就是IOC容器,使得对象之间没有了耦合关系,齿轮之间的传动全部依靠“第三方”了,
全部对象的控制权全部上缴给“第三方”IOC容器,所以叫控制反转,IOC容器成了整个系统的关键核心。

依赖注入,就是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中
依赖注入(DI)和控制反转(IOC)是从不同的角度的描述的同一件事情

优点
解耦

缺点
第一、由于引入了第三方IOC容器,生成对象的步骤变得有些复杂
第二、由于IOC容器生成对象是通过反射方式,在运行效率上有一定的损耗
第三、具体到IOC框架产品(比如:Spring)来讲,需要进行大量的配制工作,比较繁琐

一些工作量不大的项目或者产品,不太适合使用IOC框架产品

一、定义

反射是java视为动态语言的关键
反射机制允许在运行状态中,对于任意一个类,都能够知道且调用这个类的所有属性和方法

二、获得Class类的几种方式  ,Cass类是反射的根源

public class Reflection {
    public static void main(String[] args) throws ClassNotFoundException {
        Person person = new Student();
        System.out.println("这个人是"+person.name);

        //  方式一   通过对象获得
        Class c1 = person.getClass();
        System.out.println(c1.hashCode());

        //  方式二   通过forname获取
        Class  c2= Class.forName("com.yin.test.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="学生";
    }
}

 三、java内存

1、堆
  a. 存放new的对象和数组
  b. 可以被所有线程共享,不会存放别的对象引用
2、栈
  a. 存放基本变量类型(会包含基本类型的具体数值)
  b. 引用对象的变量(会存放引用在堆里面的具体地址)
3、方法区
  a. 可以被所有的线程共享
  b. 包含了所有的class和static变量
四、类的加载过程
程序主动使用某个类时,如果该类没有被加到内存中,会通过三个步骤来初始化
1、load,将类的class文件读入内存,并为之创建一个java.lang.Class对象。这个过程由类加载器完成
2、link,将类的二进制数据合并到jre中
3、initialize,jvm负责对类进行初始化

类的初始化 

public class ClassInit {
    static {
        System.out.println("main初始化");
    }

    public static void main(String[] args) throws ClassNotFoundException {
        //  主动引用
        //  Son son = new Son();

        //  反射也会产生主动调用
        // Class s = Class.forName("com.yin.test.Son");

        // 子类调用父类静态方法、变量,并不会初始化子类
        //  System.out.println(Son.b);

        // 数组,也不会初始化类
        // Son[] sons=new Son[5];

        //常量(final修饰),也不会初始化类
        System.out.println(Son.M);

    }
}

class Father{
    static int b=2;
    static {
        System.out.println("父类初始化");
    }
}

class Son extends Father{
    static {
        System.out.println("子类初始化");
        m=300;
    }
    static int m=100;
    static final int M=1;
}

类加载器的作用
将class文件字节码加载到内存中,并将静态数据转换成方法区的运行结构数据
然后在堆生成代表这个类的java.lang.Class对象,作为方法区类数据的访问入口
类缓存
标准的javase类加载器可以按要求查找类,一旦某个类被加载到类加载器,将会被缓存一段时间。
jvm垃圾回收机制可以回收这些class对象

1、自定义类加载器
2、System Classloader 系统类加载器
负责java classpath 或 java.class.path指定的目录
3、Extension Classloader 扩展类加载器
jre/lib/ext下的jar包 或 java.ext.path指定的目录
4、Bootstap Classloader 引导类加载器
无法直接获取,c++编写,jvm自带的类加载器,负责java平台核心库的装载。

public class ClassLoaders {
    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("com.yin.test.ClassLoaders").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"));
    }
}

五、使用

有了Class,如何创建类的对象

Class u = Class.forName("com.yin.pojo.User");

1、直接调用newInstance创建类的对象
  a.必须有无参构造器
  b.构造器有足够的权限

User user = u.newInstance();

2、通过getDeclaredConstructor取得构造器,然后构造器再调用newInstance

Constructor<User> dc = u.getDeclaredConstructor(int.class,String.class);
User user = dc.newInstance(17, "测试");

有了Class,如何使用field、method
1、直接通过创建的对象引用(教程说不太好,真不知道为什么)
2、通过Class拿到field、method,再使用invoke生效

User user = u.newInstance();
Method a = u.getDeclaredMethod("bbb",String.class,int.class);
//如果是申明是private,需要在使用invoke前先调用setAccessible(true)关闭权限检测
//method、field、constructor都有setAccessible方法
a.setAccessible(true);
a.invoke(user, "测试", 666);

 性能对比 (普通、反射、关闭安全的反射)

import com.yin.pojo.User;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class 性能对比 {
    public static void test1(){
        User user = new User();

        long time1=System.currentTimeMillis();
        for (int i=0;i<1000000000;i++) {
            user.getName();
        }
        long time2=System.currentTimeMillis();
        System.out.println(time2-time1);
    }
    public static void test2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User();
        Method getName = user.getClass().getDeclaredMethod("getName",null);

        long time1=System.currentTimeMillis();
        for (int i=0;i<1000000000;i++) {
            getName.invoke(user,null);
        }
        long time2=System.currentTimeMillis();
        System.out.println(time2-time1);
    }
    public static void test3() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User();
        Method getName = user.getClass().getDeclaredMethod("getName",null);
        getName.setAccessible(true);

        long time1=System.currentTimeMillis();
        for (int i=0;i<1000000000;i++) {
            getName.invoke(user,null);
        }
        long time2=System.currentTimeMillis();
        System.out.println(time2-time1);
    }

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        test1();//5
        test2();//2106
        test3();//2008
    }
}

六、泛型使用

java采用泛型擦除的机制来引入泛型,

仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型的转换问题

一旦编译完成,所有和泛型有关的类型全部擦除

import com.yin.pojo.User;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

public class 反射泛型 {
    public  void  test1(Map<String, User> map, List<User> list){
        System.out.println("test1");
    }

    public  Map<String, User>  test2(){
        System.out.println("test2");
        return null;
    }

    public static void main(String[] args) throws NoSuchMethodException {
        Method method = 反射泛型.class.getMethod("test1", Map.class, List.class);
        Type[] g = method.getGenericParameterTypes();//获取方法入参泛型参数
        for (Type type : g) {
            System.out.println(type);
            if (type instanceof ParameterizedType){
                //如果type属于参数化类型,则强转为ParameterizedType,再获得真实参数
                Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    System.out.println(actualTypeArgument);
                }
            }
        }
        System.out.println("===============================");

        method = 反射泛型.class.getMethod("test2");
        Type type = method.getGenericReturnType();//获取方法返回泛型参数
            if (type instanceof ParameterizedType){
                //如果type属于参数化类型,则强转为ParameterizedType,再获得真实参数
                Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    System.out.println(actualTypeArgument);
                }
            }
    }
}

 七、注解使用

ORM,object relation mapping对象关系映射

类和表结构对应
属性和字段对应
对象和记录对应

利用注解和反射完成 类和表结构的映射关系

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.lang.annotation.*;
import java.lang.reflect.Field;

public class 注解 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c1 = Class.forName("com.yin.test.User1");
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
        //获取类注解
        TableUser tableUser = (TableUser) c1.getAnnotation(TableUser.class);
        System.out.println(tableUser.value());

        //获取字段注解
        Field age = c1.getDeclaredField("age");
        FieldUser annotation = age.getAnnotation(FieldUser.class);
        System.out.println(annotation.columnName());
    }
}

@TableUser("db_user")
@Data
@NoArgsConstructor
@AllArgsConstructor
class User1 {
    @FieldUser(columnName = "db_id", type = "int", length = 10)
    private int id;
    @FieldUser(columnName = "db_age", type = "int", length = 10)
    private int age;
    @FieldUser(columnName = "db_name", type = "varchar", length = 10)
    private String name;
}


@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableUser {
    String value();
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldUser {
    String columnName();

    String type();

    int length();
}

 

posted @ 2021-08-21 18:35  whitewall  阅读(941)  评论(0)    收藏  举报