黑马程序员_反射与枚举

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流------

1. java的反射机制:

就是在程序的运行过程中,我们可以获取到任意一个类的字节码文件对象,然后剖析该字节码文件的成员

类中的组成:
  		成员变量				Field
  		构造方法				Constructor
  		成员方法				Method
  
  首先需要获取字节码文件对象:
  	a:	Object类中的getClass()方法
  	b:  其实每一种数据类型java都给我们提供了一个静态的class属性,可以通过这个静态的class属性来获取该类中的字节码文件对象
  	c:  可以通过Class类中的一个静态的方法获取该类的字节码文件对象: forName(String className) ,className: 要是指定的类对应的全类名;
 


2. 通过反射来获取对应的构造方法以及创建对象
获取字节码文件对象    Class clazz = Class.forName("ReflectTest01.Student") ;
 
 	public Constructor[] getConstructors() : 获取所有公有的构造方法
 	public Constructor[] getDeclaredConstructors() : 获取所有的构造方法,包含私有的
 	public Constructor getConstructor(Class... parameterTypes): 获取指定的公有的构造方法
 	public Constructor getDeclaredConstructor(Class... parameterTypes)获取指定的任意一种构造方法,包含私有的
 	
 	Class类中给我们提供了一个方法,用来直接创建该类的实例:public T newInstance()
		Object newInstance = clazz.newInstance() ;
		System.out.println(newInstance);
 
 注意当我们使用public Constructor getDeclaredConstructor(Class... parameterTypes)
 获取指定的私有的构造方法时,在创建对象之时会报错:私有的只能在本类中使用,所有就报错了!
 为了解决这个问题我们可以使用public void setAccessible(boolean flag):
 将此对象的 accessible 标志设置为指示的布尔值。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。

 3.剖析指定字节码文件中的成员变量
获取Student对应的字节码文件对象:Class clazz = Class.forName("ReflectTest01.Student") ;
 
 public Field[] getFields(): 获取公有的字段,包含从父类中继承过来的
 public Field[] getDeclaredFields(): 获取本类中所有的字段,包含私有的,但是不包含从父类中继承过来的
 public Field getField(String name): 获取指定的公有的字段,name为Student中的成员变量的名字:name,age
 public void set(Object obj, Object value): obj: 指定的对象     value: 就是要设置的值

4.通过反射剖析指定的字节码文件中的成员方法
public Method[] getMethods(): 获取公共的成员方法,包含从父类中继承过来的
 public Method[] getDeclaredMethods(): 本类中所有的成员方法,不包含从父类中继承过来的
 public Method getMethod(String name, Class... parameterTypes): 获取公有的指定成员方法
 		name: 表示方法名称    parameterTypes: 这个方法中的参数对应的class类型
 public Object invoke(Object obj, Object... args): 对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。

5  .动态代理: 本来应该自己做的事情,却请了别人来做,被请的人就是代理对象
动态代理:	本来应该自己做的事情,却请了别人来做,被请的人就是代理对象。
  Proxy
  		public static Object newProxyInstance(ClassLoader loader,
                                      Class[] interfaces,
                                      InvocationHandler h)
		返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。
 
 参数含义: 
 	loader - 定义代理类的类加载器
	interfaces - 代理类要实现的接口列表
	h - 指派方法调用的调用处理程序 
 
 InvocationHandler:
 		InvocationHandler 是代理实例的调用处理程序 实现的接口。
 		Object invoke(Object proxy, Method method, Object[] args)
             
 参数含义:
 	proxy - 在其上调用方法的代理实例
 	method:	method - 对应于在代理实例上调用的接口方法的 Method 实例。
 	args:	args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,

6 . 枚举的注意事项

定义枚举类要用关键字enum
所有枚举类都是Enum的子类
枚举类的第一行上必须是枚举项,最后一个枚举项后的分号是可以省略的,但是如果枚举类有其他的东西,这个分号就不能省略。建议不要省略
枚举类可以有构造器,但必须是private的,它默认的也是private的。枚举项的用法比较特殊:枚举(“”);
枚举类也可以有抽象方法,但是枚举项必须重写该方法
枚举在switch语句中的使用

public enum Direction {
	
	FRONT , AFTER ,LEFT , RIGHT ;
	
}

public enum Direction2 {

	FRONT("前") , AFTER("后") ,LEFT("左") , RIGHT("右");
	
	public String name ;
	
	private Direction2(String name) {
		this.name = name ;
	}
}

public enum Direction3 {
	
	FRONT("前"){
		@Override
		public void show() {
			System.out.println(name);
		}
	} , AFTER("后"){
		@Override
		public void show() {
			System.out.println(name);
		}
	} ,LEFT("左"){
		@Override
		public void show() {
			System.out.println(name);
		}
	} , RIGHT("右"){
		@Override
		public void show() {
			System.out.println(name);
		}
	};
	
	public String name ;
	
	private Direction3(String name) {
		this.name = name ;
	}
	
	public abstract void show() ;

}

public class DirectionTest {
	
	public static void main(String[] args) {
		
		// 访问这四个枚举项
		Direction front = Direction.FRONT ;
		Direction after = Direction.AFTER ;
		Direction left = Direction.LEFT ;
		Direction right = Direction.RIGHT ;
		
		System.out.println(front);
		System.out.println(after);
		System.out.println(left);
		System.out.println(right);
		
		System.out.println("-----------------------------------");
		
		Direction2 front2 = Direction2.FRONT ;
		Direction2 after2 = Direction2.AFTER ;
		Direction2 left2 = Direction2.LEFT ;
		Direction2 right2 = Direction2.RIGHT ;
		
		System.out.println(front2);
		System.out.println(after2);
		System.out.println(left2);
		System.out.println(right2);
		
		System.out.println(front2.name);
		System.out.println(after2.name);
		System.out.println(left2.name);
		System.out.println(right2.name);
	
		System.out.println("-------------------------------------");
		
		Direction3 front3 = Direction3.FRONT ;
		Direction3 after3 = Direction3.AFTER ;
		Direction3 left3 = Direction3.LEFT ;
		Direction3 right3 = Direction3.RIGHT ;
		
		System.out.println(front3);
		System.out.println(after3);
		System.out.println(left3);
		System.out.println(right3);
		
		System.out.println(front3.name);
		System.out.println(after3.name);
		System.out.println(left3.name);
		System.out.println(right3.name);
		
		System.out.println("------------------------");
		
		// 调用方法
		front3.show() ;
		after3.show() ;
		left3.show() ;
		right3.show() ;
	}

}

7. Jdk1.7的新特性
Jdk1.7的新特性
  A:二进制字面量
		JDK7开始,终于可以用二进制来表示整数(byte,short,int和long)。
		使用二进制字面量的好处是,可以使代码更容易被理解。语法非常简单,只要在二进制数值前面加 0b或者0B
		int x = 0b110110
	B:数字字面量可以出现下划线
		为了增强对数值的阅读性,如我们经常把数据用逗号分隔一样。JDK7提供了_对数据分隔。
		举例:
			int x = 100_1000;
		注意事项:
			不能出现在进制标识和数值之间
			不能出现在数值开头和结尾
			不能出现在小数点旁边
	C:switch 语句可以用字符串
	D:泛型简化
	E:异常的多个catch合并
	F:try-with-resources 语句
		try(必须是java.lang.AutoCloseable的子类对象){…}catch{...}
		好处:
			资源自动释放,不需要close()了
			把需要关闭资源的部分都定义在这里就ok了
			主要是流体系的对象是这个接口的子类(看JDK7的API)

你可能感兴趣的:(黑马程序员_反射与枚举)