一,类对象
- 类的对象:基于某个类new出来的对象,也叫实例对象
- 类对象:类加载的产物,封装了一个类所有的信息(类名,父类,接口,属性,方法,构造方法)Java源代码编译后的.class文件存储在硬盘中,从硬盘加载进内存。就是一个类对象
- 将类的各个组成部分封装为其他对象,就是反射机制
反射的好处:
1. 可以在程序运行过程中,操作这些对象。
2. 可以解耦,提高程序的可扩展性。
1.1Java代码在计算机中的三个阶段
1.2 获取Class对象的方式:
- Class.forName("包名.类名"):将字节码文件加载进内存,返回Class对象 * 多用于配置文件,将类名定义在配置文件中。读取文件,加载类 推荐写法
- 类名.class:通过类名的属性class获取,返回Class对象 * 多用于参数的传递
- 对象.getClass():getClass()方法在Object类中定义着。 * 多用于对象的获取字节码的方式
- 同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。
通用操作:
- 使用反射机制获取类对象,并使用Class对象的方法获取表示类成员的各种对象(Constructor,Method,Field),实现反射各种应用
案例,
package com.qf; import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Properties; public class TestStudent { public static void main(String[] args) throws Exception { //getClazz(); //getClazzInfo(); // getConstructors(); // getMethods(); // Properties properties=new Properties(); // ArrayList<String> arrayList=new ArrayList<String>(); // //properties.setProperty(key, value) // properties.setProperty("username", "张三"); // invokeAny(properties, "setProperty", new Class<?>[] {String.class,String.class}, new Object[] {"username","张三"}); // invokeAny(arrayList, "add", new Class<?>[] {Object.class}, new Object[] {"梓源"}); // System.out.println(properties); // System.out.println(arrayList); //getFields(); testIntrospector(); } //获取类对象 public static void getClazz() throws Exception { //(1)通过类的对象,调用getClass()方法 Student xiangrui=new Student(); Class<?> class1= xiangrui.getClass(); System.out.println(class1.hashCode()); //(2)通过类名.class Class<?> class2=Student.class; System.out.println(class2.hashCode()); //(3)通过Class.forName()静态方法获取,参数是类的全名称, 推荐写法:(1)灵活 (2)耦合性低 Class<?> class3=Class.forName("com.qf.Student"); System.out.println(class3.hashCode()); } //获取类名、包、父类、实现接口 public static void getClazzInfo() throws Exception { //1获取类对象 Class<?> class1=Class.forName("com.qf.Student"); //2获取类的全名称 System.out.println(class1.getName()); //3获取包信息 Package package1 = class1.getPackage(); System.out.println(package1.getName()); //4获取父类 Class<?> superclass = class1.getSuperclass(); System.out.println(superclass.getName()); System.out.println("-----------------"); //5获取实现接口 Class<?>[] interfaceClasses=class1.getInterfaces(); for (Class<?> class2 : interfaceClasses) { System.out.println(class2); } } //获取类的构造方法【重点】 public static void getConstructors() throws Exception { //1 获取类对象 Class<?> class1=Class.forName("com.qf.Student"); //2获取构造方法 //2.1getConstructors()获取所有的构造方法 // Constructor<?>[] constructors=class1.getConstructors(); // for (Constructor<?> constructor : constructors) { // System.out.println(constructor); // } //2.2获取无参构造方法 Constructor<?> constructor=class1.getConstructor(); //使用无参构造方法创建对象 Student student=(Student)constructor.newInstance(); System.out.println(student); //2.3获取带参构造方法 Constructor<?> constructor2=class1.getConstructor(String.class,int.class,String.class,String.class); //使用带参构造方法创建对象 Student xiangrui=(Student)constructor2.newInstance("祥睿",20,"1001","男"); System.out.println(xiangrui); //3创建对象的简便方法(默认是无参构造方法) Student student2=(Student)class1.newInstance(); System.out.println(student2); } //获取类的普通方法【重点】 public static void getMethods() throws Exception{ //获取类对象 Class<?> class1=Class.forName("com.qf.Student"); //1获取所有方法 getMethods()获取所有公开的方法,包括继承的公开方法 //Method[] methods=class1.getMethods(); //2获取所有方法 getDeclaredMethods(); 获取类中所有的方法,包括私有、保护、默认方法、不包括继承的方法。 // Method[] methods=class1.getDeclaredMethods(); // for (Method method : methods) { // System.out.println(method); // } //3获取show方法 Method methodShow=class1.getMethod("show"); //调用方法 // Student student=new Student(); // student.show(); Student student=(Student)class1.newInstance(); methodShow.invoke(student);//student.show(); //获取带参show方法 Method methodShow2=class1.getMethod("show",String.class); methodShow2.invoke(student, "110"); //获取getName()方法 Method methodGetName=class1.getMethod("getName"); String name=(String)methodGetName.invoke(student); System.out.println(name); //获取静态方法 Method methodPrintInfo=class1.getMethod("printInfo"); methodPrintInfo.invoke(null);//Student.printInfo(); //获取私有方法 Method methodPrintInfo2=class1.getDeclaredMethod("printInfo2"); //设置访问权限无效(不要用,破坏封装性) methodPrintInfo2.setAccessible(true); methodPrintInfo2.invoke(student); } //通用方法 public static Object invokeAny(Object obj,String methodName,Class<?>[] paramsType,Object... paramsValue) throws Exception { Class<?> class1=obj.getClass(); Method method=class1.getMethod(methodName, paramsType); return method.invoke(obj, paramsValue); } //使用反射操作属性 public static void getFields() throws Exception { //获取类对象 Class<?> class1 = Class.forName("com.qf.Student"); //获取属性 //getFields() 获取公开的属性、从父类继承的属性 //class1.getFields() // Field[] fields=class1.getDeclaredFields(); // for (Field field : fields) { // System.out.println(field); // } //获取name Field fieldName=class1.getDeclaredField("name"); Student ziyuan = (Student)class1.newInstance(); //调用 fieldName.setAccessible(true); fieldName.set(ziyuan, "梓源"); System.out.println(fieldName.get(ziyuan)); Field fieldAge=class1.getDeclaredField("age"); fieldAge.setAccessible(true); fieldAge.set(ziyuan, 20); System.out.println(fieldAge.get(ziyuan)); } //内省机制:使用反射技术操作属性的一种机制。 //Introspector 内省工具类 //BeanInfo 类信息 //PropertyDescriptor 属性描述符(代表一个属性) //以getXxx setXxx isXxx开头的方法叫属性 public static void testIntrospector() throws Exception { Class<?> class1=Class.forName("com.qf.Teacher"); //BeanInfo 类信息 //BeanInfo beanInfo = Introspector.getBeanInfo(class1); //PropertyDescriptor //以getXxx setXxx isXxx开头的方法叫属性 // PropertyDescriptor[] propertyDescriptors=beanInfo.getPropertyDescriptors(); // for (PropertyDescriptor pd : propertyDescriptors) { // System.out.println(pd.getName()); // } Teacher lilaoshi=(Teacher)class1.newInstance(); //获取属性描述符 PropertyDescriptor pdName=new PropertyDescriptor("name", class1); PropertyDescriptor pdAge=new PropertyDescriptor("age", class1); PropertyDescriptor pdSalary=new PropertyDescriptor("salary", class1); //赋值 pdName.getWriteMethod().invoke(lilaoshi, "李老师");//setName(); pdAge.getWriteMethod().invoke(lilaoshi, 40); pdSalary.getWriteMethod().invoke(lilaoshi, 50000); System.out.println(lilaoshi); System.out.println(pdName.getReadMethod().invoke(lilaoshi)); } }
1.2 java创建对象的四种方式:
- 使用new关键字,调用构造方法
- 使用反射技术,调用构造方法
- 使用Cloneable接口克隆对象,不会调用构造方法,必须实现接口重写clone方法
- 使用反序列化,不会调用构造方法,实现serializable接口
1.3 设计模式
- 特定问题的固定解决办法,代码设计经验的总结
- Gof设计模式中,介绍了23种
- 好处是可重用,
1.4 工厂设计模式
- 开闭原则,对拓展开放,对修改关闭
- 工厂模式主要负责对象的创建问题
- 可通过反射进行工厂模式的设计,动态完成对象创建
1.5 单例设计模式
1.5.1饿汉式写法 :缺点:声明周期比较长,浪费空间。 优点:线程安全
- 把类的构造方法变为私有的。
- 在单例类内部类创建对象并实例化
- 在单例类中添加一个公开的方法,返回这个对象
1 //饿汉式 2 public class SingleTon1{ 3 private SingleTon1(){ 4 5 } 6 private static final SingleTon1 instance = new SingleTon1(); 7 8 public static SingleTon1 getInstance(){ 9 return instance; 10 } 11 }
1.5.2 懒汉式写法:懒汉式写法: 优点:声明周期短,节省空间 缺点:线程不安全
- 把类的构造方法变为私有的。
- 在单例类内部类创建对象,没有初始化。
- 在单例类中添加一个公开的方法,返回这个对象
public class SingleTon2 { // (1)把类的构造方法变为私有的。 private SingleTon2() { } //(2)在单例类内部类创建对象,没有初始化。 private static SingleTon2 instance=null; //(3)在单例类中添加一个公开的方法,返回这个对象 public static SingleTon2 getInstance() { //100线程 ,只要有一个线程进入到synchronized中,instance一定实例化了,另外99个线程不需要判断synchronized if(instance==null) {//提高效率 另外99判断if synchronized (SingleTon2.class) { if(instance==null) { instance=new SingleTon2(); } } } return instance; } }
1.5.3 静态内部类写法
public class SingleTon3 { //1私有化构造方法 private SingleTon3() { // TODO Auto-generated constructor stub } //2创建对象(1 静态内部类不使用,不会提前加载,声明周期短,2 JVM实例化对象时解决线程安全问题) private static class Holder{ private static final SingleTon3 instance=new SingleTon3(); } //3返回这个对象 public static SingleTon3 getInstance() { return Holder.instance; } }
二,枚举
- 引用类型,规定了取值范围的数据类型
- 枚举变量不能使用其他的数据,只能使用枚举中的常量赋值,提高程序安全性
- 定义枚举使用enum关键字
- 枚举的本质:
- 是一个终止类,继承Enum抽象类
- 枚举中常量是当前类型的静态常量
/** * 定义枚举 * 关键字enum (Enumeration) * 包含 * 1 【常量】 ;可以省略 * 2 【私有构造方法、属性、方法】必须在常量的后面写 * @author wgy * */ public enum Gender { //1【常量】 MALE,FEMALE; //2 【私有构造方法、属性、方法】必须在常量的后面写 private Gender() { } private int value; public void show() { System.out.println(value); } public int getValue() { return value; } public void setValue(int value) { this.value = value; } }
三,注解
- 注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
- 程序可以读取注解,一般用于代替配置文件
- 通过反射技术获取注解,决定怎么运行类
3.1 定义注解
@interface关键字,注解中只能包含属性
3.2 注解属性类型
1 基本类型
2 String
3 Class类型
4 枚举类型
5 注解类型
以及上述类型的一维数组
@Retention(value=RetentionPolicy.RUNTIME) //@Target({ElementType.METHOD,ElementType.TYPE,ElementType.FIELD}) public @interface MyAnnotation { //public 属性 String name() default "张三"; int age(); String address(); }
3.3 元注解
用来描述注解的注解