反射是什么?
Java的反射(reflection)机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性,既然能拿到那么,我们就可以修改部分类型信息;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射(reflection)机制。
Java程序中许多对象在运行时会出现两种类型:运行时类型(RTTI)和编译时类型,
例如:Person p = newStudent();这句代码中p在编译时类型为Person,运行时类型为Student。
程序需要在运行时发现对象和类的真实信息。而通过使用反射程序就能判断出该对象和类属于哪些类。
反射相关的类:
1:Class类->代表类的实体,在运行的Java应用程序中表示类和接口
2::Field类->代表类的成员变量/类的属性
3:Method类->代表类的方法
4:Constructor类->代表类的构造方法
一个.java文件编译成.class字节码文件在JVM的堆上,
例如:Class对象包含了类的信息,Class对象只有一个
public class TestDemo {
public static void main(String[] args) {
//验证class对象只有一个
//获取class对象的三种方式:
/**
* 1.getclass
*/
Student student = new Student();
Class> c1 = student.getClass();
/**
* 2.
*/
Class> c2 = Student.class;
/**
* 3.
*/
try {
Class> c3 = Class.forName("com.fanshe.Student");//路径一定要写对
System.out.println(c1 == c2); //true
System.out.println(c2 == c3); //true
System.out.println(c1 == c3); //true
}catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
双亲委派模型:(类似于递归)
双亲委派模型的全面介绍以及优缺点:https://www.jianshu.com/p/9df9d318e838
反射优点和缺点
优点:
1. 对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法
2. 增加程序的灵活性和扩展性,降低耦合性,提高自适应能力
3. 反射已经运用在了很多流行框架如:Struts、Hibernate、Spring 等等。
缺点:
1. 使用反射会有效率问题。会导致程序效率降低。具体参考这里:http://www.imooc.com/article/293679
2. 反射技术绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂 。
枚举:
主要用途是:将一组常量组织起来。
之前定义常量:
public static final int RED = 1;
使用枚举:优点:将常量组织起来统一进行管理
public enum TestEnum {
RED("红色",1),BLACK("黑色",1),GREEN("绿色",3),WHITE("白色",4); //都属于枚举对象
}
本质:是java.lang.Enum 的子类,也就是说,自己写的枚举类,就算没有显示的继承Enum ,但是其默认继承了这个类。
Enum的常用方法:
values() 以数组形式返回枚举类型的所有成员
ordinal() 获取枚举成员的索引位置
valueOf() 将普通字符串转换为枚举实例
compareTo() 比较两个枚举成员在定义时的顺序
public enum TestEnum {
RED("红色",1),BLACK("黑色",1),GREEN("绿色",3),WHITE("白色",4); //都属于枚举对象
public String color;
public int ordinal;
TestEnum(String color,int ordinal) {
this.color = color;
this.ordinal = ordinal;
}
public static TestEnum getEnumKey (int key) {
for (TestEnum t: TestEnum.values()) {
if(t.ordinal == key) {
return t;
}
}
return null;
}
public static void main2(String[] args) {
TestEnum[] testEnums = TestEnum.values();
for (int i = 0; i < testEnums.length; i++) {
//打印内容
//System.out.print(testEnums[i]+" ");
//打印下标
//System.out.print(testEnums[i].ordinal()+" ");
}
System.out.println(TestEnum.valueOf("BLACK"));
TestEnum testEnum1 = BLACK;
TestEnum testEnum2 = TestEnum.GREEN;
System.out.println(testEnum1.compareTo(testEnum2));
System.out.println(RED.compareTo(WHITE));
}
public static void main1(String[] args) {
TestEnum testEnum2 = TestEnum.BLACK;
switch (testEnum2) {
case RED:
System.out.println("red");
break;
case BLACK:
System.out.println("black111");
break;
case WHITE:
System.out.println("WHITE");
break;
case GREEN:
System.out.println("black");
break;
default:
break;
}
}
}
枚举优点缺点
优点:
1. 枚举常量更简单安全 。
2. 枚举具有内置方法 ,代码更优雅
缺点:
1. 不可继承,无法扩展
枚举是否可以通过反射,拿到实例对象呢?
我们刚刚在反射里边看到了,任何一个类,哪怕其构造方法是私有的,我们也可以通过反射拿到他的实例对象,那
么枚举的构造方法也是私有的,我们是否可以拿到呢
答案:不能通过反射获取枚举类的实例
Lambda表达式:个人感觉就是为了简写代码用的
//函数式接口
//无返回值无参数
@FunctionalInterface
interface NoParameterNoReturn {
//注意:只能有一个方法
void test();
}
//无返回值一个参数
@FunctionalInterface
interface OneParameterNoReturn {
void test(int a);
}
//无返回值多个参数
@FunctionalInterface
interface MoreParameterNoReturn {
void test(int a,int b);
}
//有返回值无参数
@FunctionalInterface
interface NoParameterReturn {
int test();
}
//有返回值一个参数
@FunctionalInterface
interface OneParameterReturn {
int test(int a);
}
//有返回值多参数
@FunctionalInterface
interface MoreParameterReturn {
int test(int a,int b);
}
public class TestDemo {
public static void main(String[] args) {
//有返回值无参数
NoParameterReturn np = ()->{return 10;};
NoParameterReturn np2 = ()->10;
System.out.println(np.test());
System.out.println(np2.test());
//有返回值1个参数
OneParameterReturn op = (int a)->{return a;};
OneParameterReturn op2 = a -> a;
System.out.println(op.test(20));
System.out.println(op2.test(30));
//有返回值多个参数
MoreParameterReturn mr = (int a,int b)->{
return a+b;
};
System.out.println(mr.test(1, 2));
MoreParameterReturn mr2 = (a,b)-> a+b;
System.out.println(mr2.test(3, 4));
}
//无返回值
public static void main1(String[] args) {
//无返回值无参数
NoParameterNoReturn np = () ->{
System.out.println("hello");
};
np.test();
//无返回值一个参数
/*OneParameterNoReturn op = (a)->{
System.out.println(a);
};*/
OneParameterNoReturn op = a-> System.out.println(a);
op.test(10);
//无返回值多个参数
MoreParameterNoReturn mp = (int a,int b)->{
System.out.println(a+b);
};
mp.test(10,20);
}
}
变量捕获:Lambda 表达式中存在变量捕获
1,匿名内部类
public static void main2(String[] args) {
int a = 99;
//a = 88;
NoParameterNoReturn2 np = ()->{
//a = 88;
System.out.println(a);
};
np.test();
}
/**
* 匿名内部类当中捕获的常量一定是常量或者是没有改变过的量
* @param args
*/
public static void main1(String[] args) {
int a = 10;
//匿名内部类
new Test() {
public void func() {
System.out.println(a);
}
}.func();
}
2.Lambda变量捕获
Collection接口: removeIf() spliterator() stream() parallelStream() forEach()
List接口: replaceAll() sort()
Map接口:getOrDefault() forEach() replaceAll() putIfAbsent() remove() replace()
computeIfAbsent() computeIfPresent() compute() merge()
//map中的forEach
public static void main(String[] args) {
HashMap map = new HashMap<>();
map.put(1,"hello");
map.put(2,"world");
map.put(3,"hello");
map.put(4,"lambda");
map.forEach(new BiConsumer() {
@Override
public void accept(Integer integer, String s) {
System.out.println("key: "+integer+" value: "+s);
}
});
//Lambda表达式
map.forEach((key,value)-> System.out.println("key: "+key+" value: "+value));
}
public static void main4(String[] args) {
ArrayList list = new ArrayList<>();
list.add("hello");
list.add("abc");
list.add("world");
list.sort(new Comparator() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
//Lambda表达式
list.sort((o1,o2)->{return o1.compareTo(o2);});
list.sort((o1, o2) -> o1.compareTo(o2));
list.forEach((s)-> System.out.println(s));
}
//List接口forEach
public static void main3(String[] args) {
ArrayList list = new ArrayList<>();
list.add("hello");
list.add("world");
list.forEach(new Consumer() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
//Lambda表达式
list.forEach((s)-> System.out.println(s));
}