动态代理
定义
代理:本来应该自己做的事情,请了别人来做,被请的人就是代理对象
动态代理:在程序运行过程中产生的这个对象,而程序运行过程中产生对象其实
就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理对象。
java中动态代理的使用
在Java中java.lang.reflect包下提供了一个Proxy类和一个 接口,通过使用这个类和接口就可以生成动态代理对象
public static Object newProxyInstance(ClassLoader loader,Class>[] interfaces,InvocationHandler h)
最终会调用InvocationHandler的方法
InvocationHandler Object invoke(Object proxy,Method method,Object[] args)
演示
publicstaticvoidmain(String[]args)throwsException{
Studentstudent=newStudent();
//创建Student的代理对象
MyInterfacep=(MyInterface)Proxy.newProxyInstance(Student.class.getClassLoader(),Student.class.getInterfaces(),newInvocationHandler() {
@Override
publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{
System.out.println("你好");
method.invoke(student);
returnnull;
}
});
p.method();
}
原理
利用对象的类的字节码接口,写出一个新的类到本地区,通过编译器直接编译成.class文件,再通过类加载器加载进来
弊端: 代理的对象必须实现接口
cglib
定义
非java原生的动态代理, 效率更高,限制更小
可以代理没有接口的类
使用
导包
演示
publicstaticvoidmain(String[]args) {
//导入包 cglib-core asm ant ant-launcher
//创建运行器
MethodInterceptormi=newMethodInterceptor() {
@Override
publicObjectintercept(Objectarg0,Methodarg1,Object[]arg2,MethodProxyarg3)throwsThrowable{
System.out.println("运行前");
arg3.invokeSuper(arg0,arg2);
System.out.println("运行后");
returnnull;
}
};
//获取代理类
Enhancerenhancer=newEnhancer();
//设置父类
enhancer.setSuperclass(Demo.class);
//运行任务
enhancer.setCallback(mi);
//创建代理对象
Demod=(Demo)enhancer.create();
d.method();
}
总结
单例模式
模式: 针对某种问题的最优解
懒汉式, 饿汉式 , 饿汉式的变形体
如何写单例模式
私有化构造方法
提供自己创建的对象给使用者
优点 :
节省内存空间, 提升访问的速度
缺点 :
相对于静态来说, 效率还是要低一些
枚举
枚举就是多例的简写形式
枚举项的权限, 修饰符, 类型, new 省略
枚举的注意事项
类加载
就是将.class文件从硬盘上读取到内存中,变成一个java可以使用的类
类加载器
四个类加载器和他们的应用范围
根类加载器不是java代码写的
双亲委派模型
加载一个类的时候,从最底层的类加载器开始逐层上传, 一直到顶层, 整个过程要检测这个类有没有被加载过
作用 : 保持类的唯一性
反射
反射其实就是java提供的另外一种编程模式
提高了代码的兼容性, 扩展性
反射操作构造方法, 操作成员变量, 操作成员方法
default关键字
定义
1.8中允许我们给接口添加一个非抽象的方法实现, 在方法使用default关键字就可以了,这个特征又叫做拓展方法
演示
publicinterfaceMyInterface{
//使用default的关键字
publicdefaultvoidmethod(){
System.out.println("你好....");
}
}
注意事项
我们都知道, java之所以支持多实现就是应为接口中没有具体的逻辑代码, 不会造成冲突的问题, 那么1.8之后我们可以在接口中编写具体的逻辑代码了,那么多实现的时候会冲突吗 ?
肯定会冲突的,所以为了解决这个问题, 编译器要求如果多实现的时候出现了相同名称的非抽象方法的话,子类就必须重写这个方法
多实现
publicclassDemoimplementsMyInterface,MyInterface2{
@Override
publicvoidmethod() {
System.out.println("子类必须重写多个接口中相同名称的非抽象方法");
MyInterface.super.method();
}
}
二. 接口中的静态方法
定义
在接口中定义一个静态的方法, 可以有具体的代码实现
演示
publicinterfaceMyInterface{
//静态方法 只能接口自己使用
//接口中的静态方法权限必须是public的, 默认加上public
staticvoidmethod3(){
System.out.println("我是接口中的静态方法");
}
}
注意事项
子类无法使用接口中的静态方法
接口中的静态方法的权限必须是公共的,可以不写,默认是公共的
lambda表达式
定义
一种简写形式,格式精简, 很酷
每一个lambda的表达都对应一个类型,通常是接口类型的
适用于函数式接口(只有一个抽象方法的接口)
格式
(参数...) -> {执行代码} 返回一个可用的对象
当只有一句代码时,大括号可以省略, 建议省略
演示
publicstaticvoidmain(String[]args) {
List
//之前的写法
Collections.sort(list,newComparator
publicintcompare(Stringo1,Stringo2) {
returno1.compareTo(o2);
}
});
//lambda表达式的写法
Collections.sort(list, (Stringa,Stringb)->{
returna.compareTo(b);
});
System.out.println(list);
}
方法的引用
使用 : : 来引用一个类的方法
publicinterfaceDoing
publicTdoing(Kk);
}
publicstaticvoidmain(String[]args) {
//调用类中的静态方法来处理接口中方法上的参数
Doing
Integerinteger=d.doing("123");
System.out.println(integer);
}
publicstaticvoidmain(String[]args) {
//调用对象的方法
Doing
Integeri=d.doing("v");
System.out.println(i);
}
构造方法的引用
用new关键字来代替构造方法
publicclassPerson{
Stringname;
Person(Stringname) {
super();
this.name=name;
}
@Override
publicStringtoString() {
return"Person [name="+name+"]";
}
}
publicstaticvoidmain(String[]args) {
//引用对象的构造方法
Doing
Personperson=d.doing("小明");
System.out.println(person);
}
注意事项
lambda表达式指向的接口必须和调用的方法的参数一致,也就是说相当于是接口实现类中的方法调用你指向的方法
lambda表达式中访问外层作用域和老版本的匿名对象的方式很相似, 你可以直接访问标记了final的外层局部变量, 或者示例的字段以及静态变量
lambda表达式中无法访问接口中的默认方法(就是被default修饰的方法)
四. Stream接口
定义
表示能应用在一组元素上一次执行的操作序列
其实就是找了一个地方将执行了某个方法后剩下的元素存放起来
提供了许多操作集合的方法,而且原集合数据不受影响
常用的方法
filter 过滤
sorted 排序
map 转化
match 匹配
count 计数
演示
publicstaticvoidmain(String[]args) {
List
stringCollection.add("ddd2");
stringCollection.add("aaa2");
stringCollection.add("bbb1");
stringCollection.add("aaa1");
stringCollection.add("bbb3");
stringCollection.add("ccc");
stringCollection.add("bbb2");
stringCollection.add("ddd1");
//过滤出以a开头的元素并遍历
stringCollection.stream().
filter((s)->s.startsWith("a"))
.forEach(System.out::println);;
}
并行
并行Stream可以在多个线程上同时执行
publicstaticvoidmain(String[]args) {
intmax=1000000;
List
for(inti=0;i //创建随机id UUIDuuid=UUID.randomUUID(); values.add(uuid.toString()); } longt1=System.nanoTime(); //获取并行的stream longcount=values.parallelStream().sorted().count(); System.out.println(count); longt2=System.nanoTime(); System.out.println(t2-t1); } 五. Date 定义 java 8 在包java.time下包含了一组全新的时间日期API ZoneId 定义时区 publicstaticvoidmain(String[]args) { System.out.println(ZoneId.getAvailableZoneIds()); //获取某个城市的时区 ZoneIdzone1=ZoneId.of("Europe/Berlin"); ZoneIdzone2=ZoneId.of("Asia/Shanghai"); System.out.println(zone1.getRules()); System.out.println(zone2.getRules()); } LocalTime 一个没有时区信息的时间,以设置的时区为准备 publicstaticvoidmain(String[]args) { //获取所有的时区信息 System.out.println(ZoneId.getAvailableZoneIds()); //获取某个城市的时区 ZoneIdzone1=ZoneId.of("Europe/Berlin"); ZoneIdzone2=ZoneId.of("Asia/Shanghai"); LocalTimenow1=LocalTime.now(zone1); LocalTimenow2=LocalTime.now(zone2); //判断时间1以是否在时间2之前 System.out.println(now1.isBefore(now2));// true //使用ChronoUnit计算两个时间差值 longhoursBetween=ChronoUnit.HOURS.between(now1,now2); longminutesBetween=ChronoUnit.MINUTES.between(now1,now2); System.out.println(hoursBetween); System.out.println(minutesBetween); } 六.其他新特性 重复注解 可以将参数的名字保留到字节码中 Nashorn引擎 : jjs , 可以执行js代码 移除了FermGen空间,用Metaspace代替 -XX:MetaSpaceSize与-XX:MaxMetaspaceSize被代替-XX:PermSize与-XX:MaxPermSize 一阶段的知识点 了解计算机基础知识 了解的dos命令 了解java的历史 jdk的安装和环境变量的配置 进制 java的编译-运行方式 变量, 常量 数据类型(基本的8个,引用的5个) 运算符 : 算数运算符 复制运算符 关系运算符 逻辑运算符(双与双或/单与单或) 位运算符(& | ~ >> << >>>) 三元运算符 判断 循环 数组 (长度固定) 二维数组 方法 (方法的组成, 重载: 方法名相同,参数列表不同) 面向对象 如何写一个类 如何使用一个类 类和类之间的关系(重写) 抽象类和接口 多态 : 提高扩展性和兼容性 内部类 : 成员的, 静态的, 局部的, 匿名的 异常 : 最重要的时类名 常用类 Object String (方法必须记熟) StringBuffer StringBuilder Math Date SimpleDateFormat Random BigInteger BigDcimal 集合 Collection Map List Set Queue List : ArrayList: 查改快 增删慢 LInkedList: 增删快, 查改慢 Set HashSet : 去重 TreeSet : 去重 排序 Map (key不能重复) HashMap : 快 TreeMap : 排序 Collections 迭代器 迭代器运行时不能改变原集合 泛型 : 多线程 多线程的好处 多线程的创建使用 多线程的状态 锁 线程的通信 线程池 File 类 操作本地路径(文件和文件夹) 递归 流 字节流 字符流 文件流中, 除了FileInputStream和FileOutputStream之外, 其他的都是缓冲流 缓冲流有缓冲区, 使用时要注意 网络编程 ip 端口号 UDP TCP java 两种网络编程方式(主要记TCP) NIO 非阻塞 模拟多线程, 没有多线程的开销, 实质还是轮询处理, 只适合小流量高并发的场景 通道管理器 单例 多例 枚举 类加载器 反射 多态代理 注解 1 . 8 新特性 : 接口中 default static的使用 la