目录
一、内部类和匿名内部类
匿名内内部类和lambda表达式主要的区别在于
1、匿名内部类他必须实现继承类的所有方法
2、匿名内部类在重写时有override标识,而lambda没有
3、lambda表达式继承的接口只能有一个抽象方法
在使用匿名内部类的过程中,我们需要注意如下几点:
- 1、使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口。
- 2、匿名内部类中是不能定义构造函数的。
- 3、匿名内部类中不能存在任何的静态成员变量和静态方法。
- 4、匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。
- 5、匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。
匿名内部类:在类的内部定义了一个新的类
内部类的分类:
静态内部类
实例内部类
局部内部类
实际上使用内部类编写代码,可读性太差
public interface Skill {
void use(); // 释放技能的抽象方法
}
public class SkillImpl implements Skill {
@Override
public void use() {
System.out.println("Biu~biu~biu~");
}
}
public class Hero {
private String name; // 英雄的名称
private Skill skill; // 英雄的技能
public Hero() {
}
public Hero(String name, Skill skill) {
this.name = name;
this.skill = skill;
}
public void attack() {
System.out.println("我叫" + name + ",开始施放技能:");
skill.use(); // 调用接口中的抽象方法
System.out.println("施放技能完成。");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Skill getSkill() {
return skill;
}
public void setSkill(Skill skill) {
this.skill = skill;
}
}
使用匿名对象或者匿名内部类来实现调用
public class DemoGame {
public static void main(String[] args) {
Hero hero = new Hero();
hero.setName("艾希"); // 设置英雄的名称
// 设置英雄技能
hero.setSkill(new SkillImpl()); // 使用单独定义的实现类
//还可以改成使用匿名内部类
Skill skill = new Skill() {
@Override
public void use() {
System.out.println("Pia~pia~pia~");
}
};
hero.setSkill(skill);
}
同时使用匿名内部类和匿名对象
// 进一步简化,同时使用匿名内部类和匿名对象
hero.setSkill(new Skill() {
@Override
public void use() {
System.out.println("Biu~Pia~Biu~Pia~");
}
});
hero.attack();
}
二、反射
反射的主要原理是通过字符方式去调用相应的常量和方法:eg,把方法名和变量名卸载.properties文件中
获取Class对象的方式:
1. Class.forName("全类名"):将字节码文件加载进内存,返回Class对象
2. 类名.class:通过类名的属性class获取
3. 对象.getClass():getClass()方法在Object类中定义着。
Class对象功能:
* 获取功能:
1. 获取成员变量们
* Field[] getFields() 获取所有public修饰的成员变量
* Field getField(String name) 获取指定public修饰的成员变量
* Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符
* Field getDeclaredField(String name)
2. 获取构造方法们
* Constructor<?>[] getConstructors()
* Constructor<T> getConstructor(类<?>... parameterTypes)
* Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
* Constructor<?>[] getDeclaredConstructors()
3. 获取成员方法们:
* Method[] getMethods 获取所有public修饰的方法
* Method getMethod(String name, 类<?>... parameterTypes)
* Method[] getDeclaredMethods()
* Method getDeclaredMethod(String name, 类<?>... parameterTypes)
4. 获取类名
* String getName()
1、 获取成员变量们
Person.classs省略。。自己写
getFields()
public static void main(String[] args) throws Exception {
//0.获取Person的Class对象
Class personClass = Person.class;
//1.Field[] getFields()获取所有public修饰的成员变量
Field[] fields = personClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
getField()
//2.Field getField(String name)
Field a = personClass.getField("a");
//获取成员变量a 的值
Person p = new Person();
Object value = a.get(p);
System.out.println(value);
//设置a的值
a.set(p,"张三");
System.out.println(p);
getDeclaredFields() && getDeclaredField()
//Field[] getDeclaredFields():获取所有的成员变量,不考虑修饰符
Field[] declaredFields = personClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
//Field getDeclaredField(String name)
Field getd = personClass.getDeclaredField("d");
//忽略访问权限修饰符的安全检查
getd.setAccessible(true);//暴力反射
Object value2 = getd.get(p);//从p对象获取getd的值
System.out.println(value2);
2、 获取构造方法们
有参的构造器getConstructor(类<?>… parameterTypes)
public static void main(String[] args) throws Exception {
//0.获取Person的Class对象
Class personClass = Person.class;
//有参的构造器
//Constructor<T> getConstructor(类<?>... parameterTypes)
Constructor constructor = personClass.getConstructor(String.class, int.class);
//创建对象
Object person = constructor.newInstance("张三", 23);
System.out.println(person);
无参的构造器getConstructor()
//方式一
//无参的构造器
Constructor constructor1 = personClass.getConstructor();
System.out.println(constructor1);
//创建对象
Object person1 = constructor1.newInstance();
System.out.println(person1);
//方式二
//直接创建无参的构造器
Object o = personClass.newInstance();
System.out.println(o);
3、获取成员方法们
获取无参的方法
public static void main(String[] args) throws Exception {
//0.获取Person的Class对象
Class personClass = Person.class;
//获取指定名称的方法
Method eat_method = personClass.getMethod("eat");
Person p = new Person();
//执行方法eat()方法
eat_method.invoke(p);
获取有参的方法getMethod()
//执行带一个String的犯法
Method eat_method2 = personClass.getMethod("eat", String.class);
//执行方法
eat_method2.invoke(p,"饭");
获取所有public修饰的方法:getMethods()
//获取所有public修饰的方法
Method[] methods = personClass.getMethods();
for (Method method : methods) {
System.out.println(method);
String name = method.getName();
System.out.println(name);
//method.setAccessible(true);
}
4、 获取类名
//获取类名
String className = personClass.getName();
System.out.println(className);//cn.itcast.domain.Person
5、测试反射,通Properties()对象来获取方法
pro.properties文件自己去创建
public class ReflectTest {
public static void main(String[] args) throws Exception {
//1.加载配置文件
//1.1创建Properties对象
Properties pro = new Properties();
//1.2加载配置文件,转换为一个集合
//1.2.1获取class目录下的配置文件
ClassLoader classLoader = ReflectTest.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream("pro.properties");
pro.load(is);
//2.获取配置文件中定义的数据
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
//3.加载该类进内存
Class cls = Class.forName(className);
//4.创建对象
Object obj = cls.newInstance();
//5.获取方法对象
Method method = cls.getMethod(methodName);
//6.执行方法
method.invoke(obj);
}
}
编译成功
否:编译失败(接口中没有抽象方法抽象方法的个数多余1个)
```java
@FunctionalInterface
public interface MyFunctionalInterface {
//定义一个抽象方法
public abstract void method();
}
public class MyFunctionalInterfaceImpl implements MyFunctionalInterface{
@Override
public void method() {
}
}
三、函数式接口,一般配合Lambda表达式一起使用
(1)使用Lambda必须有接口,且接口只有一个抽象方法(即函数式接口)。
(2)Lambda必须可以“上下文推断”(就是依据语境推断出参数类型,这也是Lambda的一个优点,使得参数类型得以省略,更加简洁)
缺点:
(1)不容易debug模式调试;
(2)在lambda语句中强制类型转换不方便;
(3)不能再foreach中修改forEach外面的值
(4)如果不并行计算,很多时候计算速度不如传统for循环.
函数式接口:有且只有一个抽象方法的接口,称之为函数式接口
当然接口中可以包含其他的方法(默认,静态,私有)
@FunctionalInterface注解
作用:可以检测接口是否是一个函数式接口
是:编译成功
否:编译失败(接口中没有抽象方法抽象方法的个数多余1个)
@FunctionalInterface
public interface MyFunctionalInterface {
//定义一个抽象方法
public abstract void method();
}
public class MyFunctionalInterfaceImpl implements MyFunctionalInterface{
@Override
public void method() {
}
}
1、方法的参数是一个接口,所以我们可以传递接口的匿名内部类【匿名内部的作用就是减少实现类的编写】
public class Demo {
//定义一个方法,参数使用函数式接口MyFunctionalInterface
public static void show(MyFunctionalInterface myInter){
myInter.method();
}
public static void main(String[] args) {
//调用show方法,方法的参数是一个接口,所以可以传递接口的实现类对象
show(new MyFunctionalInterfaceImpl());
//调用show方法,方法的参数是一个接口,所以我们可以传递接口的匿名内部类
show(new MyFunctionalInterface() {
@Override
public void method() {
System.out.println("使用匿名内部类重写接口中的抽象方法");
}
});
}
}
2、使用Lambda表达式去重写method()方法【()代表的就是method()方法】
//调用show方法,方法的参数是一个函数式接口,所以我们可以Lambda表达式
show(()->{
System.out.println("使用Lambda表达式重写接口中的抽象方法");
});
//简化Lambda表达式
show(()-> System.out.println("使用Lambda表达式重写接口中的抽象方法"));