Java&day14

回顾

阻塞和非阻塞的概念
	阻塞:方法在没有成功的情况下会一直等待
	非阻塞:方法不管是否成功都不等待直接向下执行

同步和异步的概念
	同步:阻塞的方法有返回值类型就是同步写法
	异步:阻塞的方法没有返回值类型有回调函数就是异步写法
	
ServerSocketChannel和SocketChannel实现连接并收发信息
	NIO里面客户端发数据
	      服务端收数据
	      
Selector选择器
	select()			:与客户端的连接
	selectedkeys()		:获取集合,集合中存放的是被连接上的服务端对象
	keys()				:获取集合,集合中存放的是所有被管理的服务端对象

NIO的特点
	可以进行非阻塞操作
AIO的特点
	可以进行异步操作

1.类加载

1.类的加载

​ 当一个类第一次被使用时,会被加载到方法区,一个类只会被加载一次。

2.类的加载时机
  1. 创建类的实例。
  2. 调用类的静态变量,或者为静态变量赋值。
  3. 调用类的静态方法。
  4. 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象。
  5. 初始化某个类的子类。
  6. 直接使用java.exe命令来运行某个主类。
package com.itheima_01;

public class Test01 {
    public static void main(String[] args) {

        //1.创建类的实例
        //Student s = new Student();

        //2.调用类的静态变量,或者为静态变量赋值。
        //Student.country = "中国";

        //3.调用类的静态方法。
        //Student.method();

        //4.反射方式

        //5.初始化某个类的子类
        Student s = new Student();

        //6.直接使用java.exe命令来运行某个主类
        //运行测试类 测试类也会被加载
    }
}
3.类加载器

​ 类加载器就是把类加载到内存的工具。

  • 启动类加载器(Bootstrap ClassLoader)

  • 扩展类加载器(Extension ClassLoader) 在JDK9之后变成了平台类加载器PlatformClassLoader@e73f9ac

  • 应用程序类加载器(Application ClassLoader)

  • idea获取类加载器

    【应用程序类加载器】 的父类是 【扩展类加载器】 的父类是 【启动类加载器】

    package com.itheima_01;
    
    public class Test02 {
        public static void main(String[] args) {
    
            //获取加载Test02这个类的类加载器
            ClassLoader classLoader = Test02.class.getClassLoader();
            System.out.println(classLoader);  //AppClassLoader@18b4aac2
    
            //获取它的父类加载器
            ClassLoader parent = classLoader.getParent();
            System.out.println(parent);      //ExtClassLoader@4554617c
    
            //获取父类的父类加载器
            ClassLoader parent1 = parent.getParent();
            System.out.println(parent1);    //null
        }
    }
    

2.反射【重点】

1.反射的概念

​ 反射机制的作用是在程序的运行期间,通过类的字节码对象来获取类的成员并操作,(成员方法、成员变量、构造方法、注解)

2.获取字节码对象的三种方式
  1. 使用类名调用.class属性
  2. 使用对象调用getClass()方法
  3. 使用Class的静态方法forName()
package com.itheima_02;

public class Test01 {
    public static void main(String[] args) throws ClassNotFoundException {
        //1.使用类名调用.class属性
        Class c1 = String.class;
        Class c2 = Test01.class;

        //2.使用对象调用getClass()方法
        Class c3 = "abc".getClass();

        //3.使用Class的静态方法forName()
        Class c4 = Class.forName("java.lang.String");


        System.out.println(c1 == c2);   //false
        System.out.println(c1 == c3);   //true
        System.out.println(c1 == c4);   //true
    }
}
3.反射操作构造方法
  • 反射获取构造方法

    • Class类的方法:
      • getConstructor(Class… c) 可以获取某一个构造方法(公共的)
      • getConstructors() 可以获取所有的构造方法(公共的)
  • 反射执行构造方法

    • Constructor类的方法:

      • newInstance(Object… obj) : 执行当前构造方法创建对象。

        ​ Object… obj 表示的是创建对象时的实际参数。

    package com.itheima_02;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    import java.util.Arrays;
    
    public class Test02 {
        public static void main(String[] args) throws Exception {
    
            //获取学生类的字节码对象
            Class c = Student.class;
    
            //可以使用Class对象来获取类中的构造方法
            //getConstructor(Class... c)   可以获取某一个构造方法(公共的)
            //获取空参构造
            Constructor con = c.getConstructor();
            //获取有参构造
            Constructor con1 = c.getConstructor(String.class, int.class);
    
            //使用空参构造创建对象
            //newInstance(Object... obj) : 执行当前构造方法创建对象。
            Object obj1 = con.newInstance();
            //向下转型
            Student s1 = (Student) obj1;
            System.out.println(s1);        //Student{name='null', age=0}
    
            //使用有参构造创建对象
            Object obj2 = con1.newInstance("柳岩",38);
            System.out.println(obj2);     //Student{name='柳岩', age=38}
    
            //getConstructors()  可以获取所有的构造方法(公共的)
            Constructor[] cons = c.getConstructors();
            System.out.println(Arrays.toString(cons));
    
            //字节码对象有快捷创建对象的方式,能够直接使用空参构造创建对象
            //但是这个方法过时了,不建议使用了
            Object o = c.newInstance();
            System.out.println(o);
    
        }
    }
    
4.反射操作成员方法
  • 反射获取成员方法

    • Class类的方法:
      • getMethod(String name, Class… c) :获取一个成员方法(公共的)

        ​ String name 表示方法名称

        ​ Class… c 表示的是方法的参数的类型

      • getMethods() : 获取类中的所有方法(公共的)

  • 反射执行成员方法

    • Method类的方法:

      • Object invoke(Object obj , Object… o) :让方法执行

        ​ 第一个参数表示执行的对象

        ​ 第二个参数表示方法的实际参数

        ​ 返回值表示方法的实际返回值

package com.itheima_02;

import java.lang.reflect.Method;

public class Test03 {

    public static void main(String[] args) throws Exception {
        //获取字节码对象
        Class c = Class.forName("com.itheima_02.Student");

        //getMethod(String name, Class... c) :获取一个成员方法(公共的)
        //第一个参数:方法的方法名。   第二个参数:方法的参数类型
        //获取睡觉方法
        Method m1 = c.getMethod("sleep");
        //获取吃饭方法
        Method m2 = c.getMethod("eat", String.class);

        //getMethods() : 获取类中的所有方法(公共的)
        //包含了自己的方法和父类的方法
        Method[] methods = c.getMethods();
        
        //创建学生对象
        Student s = new Student("柳岩",38);

        //Object invoke(Object obj , Object... o)  :让方法执行
        //之前的调用:对象,方法,实参
        //s.eat("米饭");
        //反射的调用:
        m2.invoke(s, "米饭");
        //执行睡觉方法
        m1.invoke(s);
    }
}
5.暴力反射

​ 之前的方法只能获取公共的成员,暴力反射的意思就是可以强制获取类中的所有成员。不管是不是public都可以获取到。用法就是在之前的方法中间加一个词Declared

​ getMethod() getDeclaredMethod()

​ getConstructor() getDeclaredConstructor()

​ 等等每个方法都有。。。。但是我们一般不要使用,因为他打破了java的语法规范

package com.itheima_02;
import java.lang.reflect.Method;
public class Test04 {

    public static void main(String[] args) throws Exception {
        //获取字节码对象
        Class c = Class.forName("com.itheima_02.Student");

        //暴力获取这个方法
        Method m2 = c.getDeclaredMethod("eat", String.class);
        //设置强制访问
        m2.setAccessible(true);

        //创建学生对象
        Student s = new Student("柳岩",38);

        //反射的调用:
        m2.invoke(s, "米饭");
    }
}
6.反射操作成员变量【了解】

Class类中方法:

​ getField(String name) : 获取一个成员变量。参数表示成员变量的名称

​ 在类中成员变量都是私有的,建议不要暴力反射直接操作成员变量。

​ 应该调用对应的公共的setget方法。

package com.itheima_02;

import java.lang.reflect.Field;

public class Test05 {
    public static void main(String[] args) throws NoSuchFieldException {

        //获取字节码对象
        Student s = new Student();
        Class c = s.getClass();


        //getField(String name)   :获取成员变量
        Field f1 = c.getDeclaredField("name");
        System.out.println(f1);
        //接下来可以给他进行赋值,但是我们不往下写了,也不会使用这个办法。


    }
}
7.反射的作用案例演示

​ 反射是java框架的灵魂。

  • 案例演示

    学习反射不是为了代码简单。为了更加灵活。

    配置文件

    cn=com.itheima_03.Dog
    mn=eat
    

    代码

    package com.itheima_03;
    
    import java.io.FileReader;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Method;
    import java.util.Properties;
    
    public class Test {
        public static void main(String[] args) throws Exception {
    
            //不用反射:
            //看看猫怎么睡觉
            //Animal a = new Dog();
            //a.sleep();
    
            //properties键值对
            //创建对象
            Properties p = new Properties();
            //加载
            p.load(new FileReader("day14\\config.properties"));
            //根据键获取值
            String cn = p.getProperty("cn");
            String mn = p.getProperty("mn");
    
            //用反射:
            //获取字节码对象
            Class c = Class.forName(cn);
            //获取构造方法
            Constructor con = c.getConstructor();
            //执行构造方法
            Animal a = (Animal) con.newInstance();
            //获取方法
            Method m = c.getMethod(mn);
            //执行方法
            m.invoke(a);
        }
    }
    

3.注解

1.概述

​ 在java中,使用@来表示注解,注解也是类的一个组成部分。

2.注解的作用
  • 生成帮助信息

    @author      作者介绍
    @param       参数介绍
    
  • 编译检查

    @Override    			检查重写方法
    @FunctionalInterface	检查函数式接口
    
  • 功能型

    @Test		单元测试
    

4.自定义注解

1.定义格式
public @interface 注解名{
    属性
}
2.注解的属性
  • 属性的格式

    数据类型 属性名();
    
  • 数据类型

    基本数据类型
    String
    Class
    枚举
    注解
    以上类型的数组形式
    
  • 示例

    package com.itheima_04;
    
    //名叫AAA的注解
    public @interface AAA {
        //数据类型 属性名();
        int age();		//基本类型
        String name();  //String
        int[] num();    //数组类型
        Class c();      //Class类型
        BBB b();        //注解类型
    }
    
3.注意事项【重点】
  1. 属性可以定义默认值,定义了默认值,就不会要求必须赋值了

    int age() default 18;
    String name() default "柳岩";
    int[] num() default {11,22};
    
  2. 如果注解中只有一个属性需要赋值,如果属性名叫value,那么在使用注解时,可以省略键的部分

    定义:
    	String value();
    使用:
     	@AAA("男")
    
  3. 数组形式的属性中如果只有一个元素,那么可以省略大括号

    num是一个数组属性
    	 @AAA(value = "男",num=11)
    
4.元注解

​ 元注解就是给注解加的注解。

@Target

@Target
    表示注解的作用位置
    
    ElementType.FIELD       成员变量
    ElementType.METHOD      成员方法
    ElementType.TYPE        类
    
      还有别的取值我们不用,如果不设置Target默认是在任何位置都能加

@Retention

@Retention
	  表示注解的存活阶段
	  
      RetentionPolicy.SOURCE     源码阶段
      RetentionPolicy.CLASS      编译阶段
      RetentionPolicy.RUNTIME    运行阶段
         
         如果不写Retention默认会存活到CLASS
5.解析注解的属性值
package com.itheima_04;

import java.lang.annotation.Annotation;

@AAA("柳岩")
public class Test02 {
    public static void main(String[] args) {

        //反射获取注解
        Class c = Test02.class;

        //获取类的注解
        Annotation anno = c.getAnnotation(AAA.class);
        //向下转型
        AAA a = (AAA) anno;

        //获取属性值
        String value = a.value();
        System.out.println(value);   //柳岩

        int age = a.age();
        System.out.println(age);     //18  是定义的默认值
    }
}
6.案例完成测试框架
package com.itheima_04;

import java.util.HashSet;
import java.util.Set;

//假设是我们开发的一个程序,一个程序中有很多代码有很多方法,我们想要测试方法有没有异常的产生
public class MyQQ {

    public void method(){
        int[] arr = new int[4];
        arr[10] = 5;
    }

    public void method01(){
        String s = "";
        int length = s.length();
    }

    public void method02(){
        Set<String> set = new HashSet<>();
        set.add("张三");
        set.add("老王");
        set.add("赵四");

        for (String s : set) {
            if(s.equals("老王")){
                set.remove(s);
            }
        }
    }


    public void method03(){
        String s = null;
        int length = s.length();
    }
}
package com.itheima_04;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Check {
}


//测试类
public class MyTest {
    public static void main(String[] args) throws IOException {

        //创建输出流
        BufferedWriter bw = new BufferedWriter(new FileWriter("day14\\bug.txt"));

        //1.获取MyQQ类的字节码对象
        MyQQ qq = new MyQQ();
        Class c = qq.getClass();

        //2.获取类的所有方法
        Method[] methods = c.getMethods();
        //定义计数器
        int count = 0;
        //增强for遍历
        for (Method method : methods) {
            //3.判断方法是否有Check注解
            //4.如果方法有注解,就执行方法
            if (method.isAnnotationPresent(Check.class)) {
                try {
                    method.invoke(qq);
                } catch (Exception e) {
                    count++;
                    //5.如果执行出现异常把异常信息输出到文件中
                    bw.write("在" + method.getName() + "方法中:  出现了" + e.getCause() + "异常");
                    bw.newLine();
                    bw.write("-----------------------");
                    bw.newLine();
                }
            }
        }
        //写出总次数
        bw.write("本次测试发现了" + count + "个异常");
        //关流
        bw.close();
    }
}

5.动态代理【重点】

1.作用

​ 动态代理可以对一个类的方法进行动态的增强,利用反射机制在程序的运行期间对方法进行操作。

2.使用前提

​ 类必须要实现接口。

3.ArrayList使用工具类的演示
//集合
List<String> list = new ArrayList<>();
list.add("柳岩");
list.add("崔航");
list.add("奥利给");

//工具类
//返回的是list的代理对象
//代理对象和被代理对象相当于真假对象,这两个对象非常相似,用list2去代替list
//孙悟空list     六耳猕猴list2
//List<String> list2 = Collections.unmodifiableList(list);
4.案例:不允许集合增删改
package com.itheima_05;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

@SuppressWarnings("all")
public class Test01 {
    public static void main(String[] args) {
        //集合
        List<String> list = new ArrayList<>();
        list.add("柳岩");
        list.add("崔航");
        list.add("奥利给");

        List<String> list2 = method(list);

        boolean b = list2.add("石原里美");

    }

    //我返回的这个集合是一个代理对象
    //不让调用增删改方法
    public static List<String> method(List<String> list){
        /*
            三个参数:
                ClassLoader loader      类加载器
                Class<?>[] interfaces   接口
                InvocationHandler h     匿名内部类

            返回值:
                Object          代理对象
         */
        List<String> obj = (List<String>)Proxy.newProxyInstance(list.getClass().getClassLoader(), list.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            /*
                在使用代理对象调用任何方法时,都会进入到invoke方法中
                   三个参数:
                    Object proxy    代理对象(在这里不使用他)
                    Method method   代表被代理对象调用的方法
                    Object[] args   代表调用方法时传入的实际参数

                   返回值:
                     Object   代表执行完方法之后的返回值
             */
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //执行任何方法都会都到这里来
                String name = method.getName();
                if(name.equals("add") || name.equals("set") || name.equals("remove")){
                    //判断如果是增删改方法
                    //直接给他产生异常
                    throw new RuntimeException("不允许调用增删改方法");
                }else{
                    //判断如果不是增删改方法
                    //就让他正常执行
                    Object obj = method.invoke(list, args);

                    return obj;
                }
            }
        });

        return obj;
    }
}
5.案例:集合只允许添加四个字的字符串
package com.itheima_05;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

@SuppressWarnings("all")
public class Test02 {
    public static void main(String[] args) {

        //集合
        List<String> list = new ArrayList<>();
        list.add("柳岩");
        list.add("石原里美");


        List<String> list2 = method(list);

        //list2.add("崔航");
        list2.add("新垣结衣");
        String s = list2.get(1);
        System.out.println(s);


        System.out.println(list);
    }



    //写一个动态代理的方法
    //生成一个代理对象,功能代理对象只允许添加四个字的字符串
    public static List<String> method(List<String> list){

        List<String> o = (List<String>) Proxy.newProxyInstance(list.getClass().getClassLoader(), list.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                //判断是不是添加方法
                if(method.getName().equals("add")){
                    //要求:参数的长度必须是4
                    String s = (String) args[0];
                    if(s.length() != 4){
                        throw new RuntimeException("只允许添加长度为4的字符串!!!");
                    }
                }

                //其他方法都正常执行
                Object obj = method.invoke(list, args);
                return obj;
            }
        });
        return o;
    }
}

6.Lombok插件

import lombok.*;

@Data
//@Setter
//@Getter
//@ToString
//@EqualsAndHashCode
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private String name;
    private int age;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值