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(); }

浙公网安备 33010602011771号