1 反射(reflect) 是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法. 对于任意 一个对象,都能够调用它的任意方法和属性. 既然能拿到那么,我们就可以修改部分类型信息. 这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制.
2 使用场景: 可以获取到某个类对象, 以及遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的 反射机制通过反射获取到某些 私有的成员或方法.
(1) Class类 代表类的实体,在运行的Java应用程序中表示类和接口 .
(2) Field类 代表类的成员变量/类的属性 .
(3) Method类 代表类的方法
(4) Constructor类 代表类的构造方法
3-1 获得Class对象的三种方式.
(1) 使用 Class.forName(“类的全路径名”), 是静态方法. 前提是 已明确类的全路径名.
Class catClass = Class.forName("java15_0418.Cat");
(2) 使用 类名.class 方法. 仅适合在编译前就已经明确要操作的类.
Class catClass2 = Cat.class;
System.out.println(catClass == catClass2);
(3) 使用 类对象.getClass() 方法.
Cat cat = new Cat("小黑");
Class catClass3 = cat.getClass();
结论: 得到的类对象在内存中只有一份, 不管通过哪种方式获取到的类对象, 本质上都是同一个对象.所以三个都相等.
3-2 通过Class对象可以创建实例.
3-3 通过反射 获取/修改属性(可以修改 private 的属性).
package java15_0418;
class Cat {
private String name;
public Cat(String name) {
this.name = name;
}
public void eat(String food) {
System.out.println(this.name + " 正在吃 " + food);
}
}
Class catClass = Class.forName("java15_0418.Cat");
// 通过 getDeclaredField 能得到局部内容. 通过 Field 对象来表示
Field filed = catClass.getDeclaredField("name");
// 这个代码加上之后, 才能访问 private 的成员
filed.setAccessible(true);
Cat cat = new Cat();
filed.set(cat, "小喵喵"); //这个代码相当于cat.name="小喵喵"
String name = (String) filed.get(cat); //这个代码相当于cat.name
System.out.println(name);
3-4 通过反射获取到类中的方法.
Class catClass = Class.forName("java15_0418.Cat");
// 方法是可以重载的. 就可以通过后续的变长参数列表来指定, 要获取哪个版本的 eat.
// 下面这个代码的意思是获取到 只有一个 参数 且类型为 String 的 eat 方法
Method method = catClass.getMethod("eat", String.class);
Cat cat1 = new Cat();
method.invoke(cat1, "猫粮");
3-5 获取构造方法, 借助构造方法来实例化对象.
Class catClass5 = Class.forName("java15_0418.Cat");
// 获取到 Cat 类中, 只有一个参数且类型为 String 的构造方法
Constructor constructor = catClass5.getConstructor(String.class);
Cat cat5 = (Cat) constructor.newInstance("小黑");
cat5.eat("鱼");
4 反射优点和缺点.
优点:
(1) 对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法.
(2) 增加程序的灵活性和扩展性,降低耦合性,提高自适应能力.
(3) 反射已经运用在了很多流行框架如:Struts、Hibernate、Spring 等等.
缺点:
(1) 我们认为反射是一个“自省”的过程,所以在性能上面有性能的问题, 一般不建议用在小型程序上,可用到框架当中.
(2) 反射技术绕过了源代码的技术,因而会带来维护问题. 反射代码比相应的直接代码更复杂 .
5 枚举: 是将一组常量组织起来.
public enum Sex {
MALE,
FEMALE,
OTHER,
}
public class TestEnum {
public static void main(String[] args) {
// 通过刚才定义常量来表示性别, 代码可读性是提高了, 但是对于下面的场景
// 编译器并没有明确的约束. 按理説这个代码是无意义的, 但是编译仍然能正常编译.
Sex sex=Sex.valueOf("MALE");
if(sex==Sex.MALE){
System.out.println("得到一个MALE类型的枚举常量");
}
}
}
6 优点: (1) 枚举常量更简单安全 . (2) 枚举具有内置方法 ,代码更优雅
缺点:不可继承,无法扩展.
7 (1) 枚举本身就是一个类,其构造方法默认为私有的,且都是默认继承与 java.lang.Enum.
(2) 枚举可以避免反射和序列化问题 .
8 Lambda表达式的 优点很明显,在代码层次上来说使代码变得非常简洁.
缺点 也明显, 使代码变得不易读,也不易进行调试.
用 普通方法创建线程
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("使用匿名类创建 Runnable 子类对象");
}
});
用 lambda表达式创建线程:
Thread t = new Thread(() -> {
System.out.println("使用匿名类创建 Thread 子类对象");
});