A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

就业班day-11--网络编程

网络编程基础软件结构介绍C/S结构:
        全称为Client/Server结构, 是指 客户端 和 服务器 结构
        常见程序有QQ, 迅雷等软件
B/S结构:
        全称为Browser/Server结构, 是指 浏览器 和 服务器 结构
        常见浏览器有IE, 谷歌, 火狐等

网络通信协议
网络通信协议:
        通信协议是对计算机必须遵守的规则, 只有遵守这些规则, 计算机之间才能进行通信.
        协议中对数据的传输格式, 传输速率, 传输步骤等做了统一规定, 通信双方必须同时遵守, 最终完成数据交换
TCP/IP协议:
        Transmission Control Protocol/Internet Protocol, 传输控制协议/因特网互联协议.
        它定义了计算机如何连入因特网, 以及数据如何在它们之间传输的标准. 它的内部包含一系列的用于处理数据通信的协议, 并采用了4层的分层模型, 每一层都呼叫它的下一层所提供的协议来完成自己的需求

网络通信协议分类
UDP: User Datagram Protocol, 用户数据报协议
        特点:
                1. 无连接的不可靠协议
                2. 数据按包发送, 64K一个包
                3. 速度快效率高, 容易丢包
        用于视频直播, 网络电话
TCP: Transmission Control Protocol, 传输控制协议
        特点:
                1. 需要建立连接的可靠协议
                2. 数据传输无大小限制
                3. 速度慢效率低

        用于文件下载, 浏览网页

TCP通信的三次握手: TCP协议中, 在发送数据的准备阶段, 客户端与服务器之间的三次交互, 以保证连接的可

        1. 客户端向服务端发送验证信息, 等待服务器确认
        2. 服务端收到验证信息后, 回复客户端验证信息, 同时发送自己的一条验证信息
        3. 客户端收到服务端回复的信息, 确认自己之前发的信息无误, 并再次向服务器发回服务端的验证信息


网络编程三要素: IP地址
网络编程三要素:
        1. 通信协议
        2. IP地址
        3. 端口号            
IP地址: 互联网协议地址(Internet Protocol Address). 是网络中计算机的唯一标识
        版本:
                IPv4: 192.168.1.2
                IPv6: ABCD:EF01:2345:6789:ABCD:EF01:2345:6789
        特殊的IP地址: "127.0.0.1", "localhost", 都代表自己的电脑
常用DOS命令:
        // 查看自己电脑的IP地址
        ipconfig
        // 查看是否能连接到指定IP地址
        ping IP地址
        ping 192.168.31.2
网络三要素: 端口号
端口号: 计算机中进程的唯一标识
        端口号的取值范围: 0~65535的整数, 其中0~1024不建议使用
注意:
        通信的两端是2个计算机中的2个程序在相互通信, 所以2个程序都要有端口号. 端口号可以相同, 也可以不同, 相互之间能识别就行

TCP通信TCP通信程序概述(上)
java.net.ServerSocket类: TCP服务端
        // 构造方法
        ServerSocket(int port): 创建一个TCP服务端, 并监听指定端口
        // 成员方法
        Socket accept(): 监听数据, 会阻塞. 收到数据后返回Socket对象
        void close(): 关闭服务端ServerSocket
java.net.Socket类: TCP客户端
        // 构造方法
        Socket(String ip, int port): 创建TCP客户端对象
        // 成员方法
        OutputStream getOutputStream(): 获取输出流对象, 用于发送数据
        InputStream getInputStream(): 获取输入流, 用于接收数据
        void shutdownOutput(): 关闭输出流, 告知服务端数据发送完毕
        void close(): 关闭客户端Socket
TCP严格区分为 客户端(Client) 与 服务端(Server)
两端通信时步骤:
        1. 服务端程序需要先启动, 等待客户端的连接
        2. 客户端主动连接服务器端, 连接成功才能通信. 服务端不可以主动连接客户端
两端之间以 IO字节流 进行通信
一个服务端可以和多个客户端同时通信
TCP通信方式概述(下)
服务端(ServerSocket)可以通过 accept() 方法等待一个客户端(Socket)主动连接, 从而得到一个客户端对象(Socket), 来识别不同的客户端
服务端(ServerSocket)没有IO流, 是通过获取到每个客户端对象(Socket)的IO流来进行通信的.
        使用"客户端的InputStream"读取客户端发来的数据
        使用"客户端的OutputStream"向客户端回写数据

TCP程序: 客户端代码实现
java.net.Socket类: TCP客户端
        // 构造方法
        Socket(String ip, int port): 创建TCP客户端对象
        // 成员方法
        OutputStream getOutputStream(): 获取输出流对象, 用于发送数据
        InputStream getInputStream(): 获取输入流, 用于接收数据
        void shutdownOutput(): 关闭输出流, 告知服务端数据发送完毕
        void close(): 关闭客户端Socket      
实现步骤:
        1.创建一个客户端对象 Socket, 构造方法绑定服务器的IP地址和端口号
        2.使用Socket对象中的方法 getOutputStream() 获取网络字节输出流OutputStream对象
        3.使用网络字节输出流OutputStream对象中的方法 write(), 给服务器发送数据
        4.使用Socket对象中的方法 getInputStream() 获取网络字节输入流InputStream对象
        5.使用网络字节输入流InputStream对象中的方法 read(), 读取服务器回写的数据
        6.释放资源(Socket)
注意:
        1.客户端和服务器端进行交互, 必须使用Socket中提供的网络流, 不能使用自己创建的流对象
        2.当我们创建客户端对象Socket的时候, 就会去请求服务器和服务器经过3次握手建立连接通路
                这时如果服务器没有启动, 那么就会抛出异常ConnectException: Connection refused: connect
                如果服务器已经启动, 那么就可以进行交互了

TCP程序: 服务器端代码实现
java.net.ServerSocket类: TCP服务端
        // 构造方法
        ServerSocket(int port): 创建一个TCP服务端, 并监听指定端口
        // 成员方法
        Socket accept(): 监听数据, 会阻塞. 收到数据后返回Socket对象
        void close(): 关闭服务端ServerSocket      
服务器的实现步骤:
        1.创建服务器ServerSocket对象和系统要指定的端口号
        2.使用ServerSocket对象中的方法 accept(), 获取到请求的客户端对象Socket
        3.使用Socket对象中的方法 getInputStream() 获取网络字节输入流InputStream对象
        4.使用网络字节输入流InputStream对象中的方法 read(), 读取客户端发送的数据
        5.使用Socket对象中的方法 getOutputStream() 获取网络字节输出流OutputStream对象
        6.使用网络字节输出流OutputStream对象中的方法 write(), 给客户端回写数据
        7.释放资源(Socket,ServerSocket)

今日API
java.net.ServerSocket类: TCP服务端
        // 构造方法
        ServerSocket(int port): 创建一个TCP服务端, 并监听指定端口
        // 成员方法
        Socket accept(): 监听数据, 会阻塞. 收到数据后返回Socket对象
        void close(): 关闭服务端ServerSocket
java.net.Socket类: TCP客户端
        // 构造方法
        Socket(String ip, int port): 创建TCP客户端对象
        // 成员方法
        OutputStream getOutputStream(): 获取输出流对象, 用于发送数据
        InputStream getInputStream(): 获取输入流, 用于接收数据
        void shutdownOutput(): 关闭输出流, 告知服务端数据发送完毕
        void close(): 关闭客户端Socket

就业办day-12- 函数式接口
函数式接口
函数式接口概念, 自定义函数式接口
函数式接口: JDK 8 新特性
    有且仅有一个抽象方法的接口, 适用于函数式编程场景的接口
    (默认方法, 静态方法, 私有方法, 与java.lang.Object类中定义相同的抽象方法, 都不算作抽象方法)
自定义函数式接口:
        接口中有且只有一个抽象方法
@FunctionalInterface的作用:

        在接口上使用, 检测当前的接口是否为函数式接口

函数式接口的使用
函数式接口的使用: 代替匿名内部类方式
函数式编程性能浪费的日志案例
日志: 就是存储程序运行信息的文本文件.
    我们平时打印输出一些信息是在控制台上, 如果将这些信息写入文本文件, 这些文件就是日志

使用Lambda延迟执行的特性优化日志案例
Lambda具有延迟执行的特点:
        传递Lambda对象, 只有当符合执行条件时, 才会执行代码

java.util.function.Supplier<T>函数式接口: 生产型函数式接口
        // 抽象方法
         T get(): 用于获取一个对象或值. 至于获取什么值, 怎么获取, 需要我们根据应用场景编写Lambda来实现

Consumer消费型函数式接口
java.lang.StringBuilder类: 可变字符序列, 类似于String, 线程不安全效率高   "abc" -> "cba"
        StringBuilder reverse(): 将StringBuilder内部保存的内容反转
        String toString(): 转换为String   new StringBuilder("abc").reverse().toString()  "cba"
java.lang.StringBuffer类: 可变字符序列, 类似于String, 线程安全效率低
        StringBuffer reverse(): 将StringBuffer内部保存的内容反转
        String toString(): 转换为String
java.util.function.Consumer<T>函数式接口: 消费型函数式接口
        // 抽象方法
        void accept(T t): 用于消费(使用)一个对象或值. 至于怎么消费, 需要我们根据应用场景编写Lambda来实现
        // 默认方法
        default Consumer<T> andThen(Consumer<? super T> after): 拼接两个Consumer接口的Lambda对象实现连续操作. 谁写前面, 谁先消费


Predicate条件判断函数式接口
java.util.function.Predicate<T>函数式接口: 条件接口, 用于判断
        // 抽象方法
        boolean test(T t): 判断参数传递的对象. 至于怎么判断, 要判断什么, 需要我们编写Lambda表达式来实现
        // 默认方法 (用于连接多个判断条件)
        default Predicate<T> and(Predicate<? super T> other): 与 &&
        default Predicate<T> or(Predicate<? super T> other): 或  ||
        default Predicate<T> negate(): 非, 取相反结果   !

Function转换型函数式接口
函数 y = f(x)
java.util.function.Function<T,R>: 根据一个 T类型的数据 转换为 另一个R类型的数据
        T称为前置条件, 也就是输入(input)的类型
        R称为后置条件, 也就是返回结果(result)的类型
        有进有出, 所以称为"函数Function"
        // 抽象方法
        R apply(T t): 将T转换为R
        // 默认方法
        default <V> Function<T, V> andThen(Function<? super R, ? extends V> after): 拼接多个Function转换

今日API
java.util.function.Supplier<T>函数式接口: 生产型函数式接口
        // 抽象方法
         T get(): 用于获取一个对象或值. 至于获取什么值, 怎么获取, 需要我们根据应用场景编写Lambda来实现      
java.util.function.Consumer<T>函数式接口: 消费型函数式接口
        // 抽象方法
        void accept(T t): 用于消费(使用)一个对象或值. 至于怎么消费, 需要我们根据应用场景编写Lambda来实现
        // 默认方法
        default Consumer<T> andThen(Consumer<? super T> after): 拼接两个Consumer接口的Lambda对象实现连续操作. 谁写前面, 谁先消费     
java.util.function.Predicate<T>函数式接口: 条件接口, 用于判断
        // 抽象方法
        boolean test(T t): 判断参数传递的对象. 至于怎么判断, 要判断什么, 需要我们编写Lambda表达式来实现
        // 默认方法 (用于连接多个判断条件)
        default Predicate<T> and(Predicate<? super T> other): 与
        default Predicate<T> or(Predicate<? super T> other): 或
        default Predicate<T> negate(): 非, 取相反结果      
java.util.function.Function<T,R>: 根据一个T类型的数据得到另一个R类型的数据
        T称为前置条件, 也就是输入(input)的类型
        R称为后置条件, 也就是返回结果(result)的类型
        有进有出, 所以称为"函数Function"
        // 抽象方法
        R apply(T t): 将T转换为R
        // 默认方法
        default <V> Function<T, V> andThen(Function<? super R, ? extends V> after): 拼接多个Function转换
就业班day-13-Stream流

使用Stream流式思想遍历集合进行过滤Stream流式思想:
        JDK 8 出现, 是函数式编程中的一大特性
        关注做什么, 而不是怎么做

流式思想概述
Stream流式思想处理数据的方式:
        让代码像流水线一样, 一步一步的对数据进行处理, 得到最终的结果
        流也可以看作是一个容器, 里面可以装很多元素, 形成元素流
流相比于集合的2个优点:
        1. Pipelining(管道特性)
                Stream流对象的一些方法调用完毕后, 会返回新的Stream流对象, 类型相同, 可链式调用, 类似于"管道"
        2. 内部迭代特性:
                集合遍历通过 Iterator 或者 增强for, 显式的在集合外部进行迭代, 这叫做外部迭代
                Stream提供了内部迭代的方法 forEach(), 可以直接调用遍历方法
使用Stream流的3个步骤:
        1. 获取数据源 (集合, 数组)
        2. 数据转换

        3. 获得结果
2种获取Stream流的方式
获取Stream流对象的2种方式:
        1. 利用Collection接口中的默认方法 default Stream<E> stream() 方法: 集合转Stream对象
        2. 利用Stream接口中的静态方法 static<T> Stream<T> of(T... values): 数组转Stream对象      
java.util.Collection<E>接口:
        // 默认方法
        default Stream<E> stream(): 将"集合"转换为Stream对象      
java.util.stream.Stream<T>接口: 管道接口, 泛型为流中元素的类型
        // 静态方法
        static<T> Stream<T> of(T... values): 将"数组"转换为Stream对象

Stream API: 方法分类, forEach()遍历
延迟方法: (具有延迟执行的特性)

Stream流的特点: 只能使用一次
每次调用延迟方法返回的Stream流对象, 都是经过处理后返回的新的Stream流对象
之前的Stream流在调用方法后, 已经使用过并关闭了, 不能再次使用, 否则会抛出异常:
        java.lang.IllegalStateException: stream has already been operated upon or closed
Stream API: map()映射转换
java.util.stream.Stream<T>接口: 管道接口
        // 抽象方法
        <R> Stream<R> map(Function<T, R> mapper): 将当前流中的T类型的元素, 转换R类型元素, 放入新流并返回
        R apply(T t)

Stream API: count()统计流中元素个数
java.util.stream.Stream<T>接口: 管道接口
        // 抽象方法
        long count(): 获取流中的元素个数 (终结方法)

Stream API: limit()获取前n个(只要前n个)
java.util.stream.Stream<T>接口: 管道接口
        // 抽象方法
        Stream<T> limit(long maxSize): 从流中获取前maxSize个. 如果maxSize大于等于元素个数, 则返回所有元素的流

Stream API: skip()跳过前n个(不要前n个)
java.util.stream.Stream<T>接口: 管道接口
        // 抽象方法
        Stream<T> skip(long n): 从流中跳过n个元素, 获取后面的元素. 如果n大于等于元素个数, 则全都跳过
Stream API: 静态方法concat()合并两个流
java.util.stream.Stream<T>接口: 管道接口
        // 静态方法
        static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b): 合并两个流的元素, 变成一个新的流. 两个流中的元素类型必须相同, 或有共同的父类

方法引用方法引用基本介绍
方法引用: Method Reference
        如果Lambda表达式仅仅是调用一个已经存在的方法, 那就可以通过方法引用来替代Lambda表达式
        作用: 简化Lambda表达式
        :: 方法引用运算符, 它所在的表达式被称为方法引用
Lambda表达式写法:
        (String s) -> System.out.println(s)   
    参数传递给System.out.println()方法去打印
方法引用写法:     
        System.out::println
        用System.out.println()方法中代码, 来作为Lambda中重写方法的实现方式
注意:
        Lambda 中 传递的参数 一定是方法引用中 的那个方法可以接收的类型,否则会抛出异常
        返回值类型 是 Stream接口自身类型的方法, 支持链式调用
                filter(): 过滤
                map(): 映射/转换
                limit(): 截取
                skip(): 跳过
终结方法:
        返回值类型 不是 Stream接口自身类型的方法, 不支持链式调用
        forEach(): 遍历
        count(): 统计

Stream API: filter()过滤
java.lang.String类:
        boolean startsWith(String prefix): 判断当前字符串是否以参数字符串开头
java.util.stream.Stream<T>接口: 管道接口
        // 抽象方法
        Stream<T> filter(Predicate<? super T> predicate): 过滤符合条件的结果. 返回过滤后的流        
        boolean test(String name)

方法引用能简化以下场景: (方法名后不要写小括号)
        1. 通过对象名引用成员方法       对象名::成员方法名  System.out::println
        2. 通过类名引用静态方法         类名::静态方法名   i -> Math.abs(i)   Math::abs
        3. 通过super引用父类成员方法    super::父类方法名  ()->super.eat();   super::eat
        4. 通过this引用本类成员方法     this::本类方法名   ()->this.eat();    this::eat
        5. 引用某个类的构造方法         类名::new          name->new Person(name)  Person::new
        6. 引用创建数组的方法           数据类型[]::new    length->new int[length];  int[]::new

方法引用: 通过对象名引用成员方法
通过对象名引用成员方法
        对象名::成员方法名     
适用场景:
        当Lambda表达式中, 仅仅是"通过某个对象调用已有的方法"时, 就可以用这种方式简化

方法引用: 通过类名引用静态方法通过类名引用静态方法
        类名::静态方法名  Math.abs(1)   Math::abs
        
适用场景:
        当Lambda表达式中, 仅仅是"通过某个类名调用已有的静态方法"时, 就可以用这种方式简化

方法引用: 通过super引用父类成员方法通过super引用父类成员方法
        super::父类方法名     
适用场景
        当Lambda表达式中, 仅仅是"调用父类某个已有的方法"时, 就可以用这种方式简化

方法引用: 通过this引用本类成员方法
通过this引用本类成员方法
        this::本类方法名   
适用场景:
        当Lambda表达式中, 仅仅是"调用本类中某个已有的方法"时, 就可以用这种方式简化

方法引用: 类的构造方法引用引用某个类的构造方法
        类名::new
使用场景
        当Lambda表达式中, 仅仅是"调用某个类的构造方法来创建一个对象"时, 就可以用这种方式简化

方法引用: 数组的构造方法引用
引用创建数组的方法
        数据类型[]::new
使用场景
        当Lambda表达式中, 仅仅是"创建一个数组对象"时, 就可以用这种方式简化

今日API
java.util.Collection<E>接口:
        // 默认方法


        default Stream<E> stream(): 将"集合"转换为Stream对象      
java.util.stream.Stream<T>接口: 管道接口, 泛型为流中元素的类型
        // 静态方法
        static<T> Stream<T> of(T... values): 将"数组"转换为Stream对象
        static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b): 合并两个流为新流
        // 抽象方法
        void forEach(Consumer<? super T> action): 遍历流中的元素进行逐一消费 (终结方法)
        long count(): 获取流中的元素个数 (终结方法)
        Stream<T> filter(Predicate<? super T> predicate): 过滤符合条件的结果. 返回过滤后的流
        <R> Stream<R> map(Function<? super T, ? extends R> mapper): 将T元素转换为R元素, 返回新的流
    Stream<T> limit(long maxSize): 从流中获取前maxSize个
    Stream<T> skip(long n): 从流中跳过n个元素, 获取后面的元素
方法引用能简化以下场景: (方法名后不要写小括号)
        1. 通过对象名引用成员方法       对象名::成员方法名
        2. 通过类名引用静态方法         类名::静态方法名
        3. 通过super引用父类成员方法    super::父类方法名
        4. 通过this引用本类成员方法     this::本类方法名
        5. 引用某个类的构造方法         类名::new
        6. 引用创建数组的方法           数据类型[]::new

day-14-反射 注解
JUnit单元测试 JUnit: 测试概述
测试:    测试代码是否正确, 能否达到预期效果    public int 除(int a, int b) {        if (b == 0) {            // 补救措施        }        return a / b;    }    除(2, 0);   
测试分类:    1. 黑盒测试:不需要写代码, 给输入值, 看程序是否能够输出期望的值        比如你下载一个APP, 随便点点点, APP闪退了   
2. 白盒测试:需要写代码的. 关注程序具体的执行流程        比如今天学习的JUnit
大 ->集成测试 (多个人, 多个模块) 接口测试 (网络请求的接口) 单元测试 (测试每个定义的方法) -> 小
JUnit: 使用步骤
知识点:
大 集成测试 (多个人, 多个模块) 接口测试 (网络请求的接口) 单元测试 (测试每个定义的方法) 小
JUnit的使用步骤 如何根据颜色判断JUnit测试成功还是失败 如何通过 assert断言 来判断结果    int result = add(1,2)    // 判断result的值是否和我们期望的一样: 断言(判断) assert
总结:
JUnit使用步骤:   

1. 定义一个测试类(也叫测试用例)        包名:xxx.xxx.xx.test        被测试的类名:   Calculator            对应的测试类名: CalculatorTest   
2. 定义测试方法:可以独立运行        被测试的方法名:       add()               对应的测试方法名: testAdd()              建议测试方法的返回值是void, 参数列表是空参   
3. 在方法上加 @Test 注解   
4. 在 @Test 注解上按 Alt+Enter, 选择 "Add 'JUnit4' to Classpath" 导入JUnit依赖环境   
5. 在方法名上右键, 选择 "Run '方法名()'"             判定结果:    红色:失败    绿色:成功.(测试通过)    断言: Assert    使用断言操作来判断结果是否符合预期:
        Assert.assertEquals(期望的结果, 运算的结果);
        如果 期望的结果 和 运算的结果 相等, 则认为测试通过, 否则测试失败    测试失败的原因提示:    java.lang.AssertionError:     Expected :1    (表示我期望得到的是1)    Actual   :-1   (但是实际得到的是-1)

JUnit: @Before, @After
@Before: 修饰的方法会"在每个测试方法执行 之前"被执行 @After:  修饰的方法会"在每个测试方法执行 之后"被执行
注意:    @Before, @After 修饰的方法可以有多个, 但是谁先执行是由JUnit内部来决定的, 没有明显的规律    所以不要写多个@Before, @After 修饰的方法
反射:

框架:    半成品软件. 可以在框架的基础上进行软件开发, 简化编码    比如JUnit就是一个单元测试框架, 它不是一个独立的软件, 而是和我们开发的软件结合, 简化代码测试   
反射: 将类的各个组成部分, 封装为其他对象, 这就是反射机制    成员变量(字段): Field类的对象    构造方法: Constructor类的对象    成员方法: Method类的对象    好处:        1. 可以在程序运行过程中, 操作这些对象        2. 可以解耦, 提高程序的可扩展性        
Java代码在计算机中的3个阶段:    SOURCE: 源代码阶段    CLASS: 类对象阶段    RUNTIME: 运行时阶段
反射: 获取字节码对象的3种方式
获取一个类的字节码对象的3种方式:   
1. Class.forName("全类名")        将字节码文件加载进内存,返回Class对象        适用场景: 多用于配置文件,将类名定义在配置文件中. 读取文件, 加载类   
2. 类名.class     通过类名的属性class获取        适用场景: 多用于参数的传递  getConstructor(String.class, int.class)   
3. 对象.getClass()        getClass()方法在Object类中定义        适用场景: 多用于对象的获取字节码的方式 p.getClass()        同一个类的字节码对象, 只有"唯一的一个"
反射: Class的方法概述
java.lang.Class<T>类: 表示一个类的字节码对象, 其中包含该类中定义的内容 // 成员方法 //
1. 获取成员变量们    Field[] getFields(): 获取所有 public 的成员变量    Field getField(String name): 获取指定名称的 public 的成员变量    Field[] getDeclaredFields(): 获取所有的成员变量, 不考虑权限修饰符    Field getDeclaredField(String name): 获取指定名称的成员变量, 不考虑权限修饰符 //
2. 获取构造方法们    Constructor<?>[] getConstructors(): 获取所有 public 的构造方法    Constructor<T> getConstructor(Class<?>... parameterTypes): 获取指定的 public 构造方法    Constructor<?>[] getDeclaredConstructors(): 获取所有的构造方法, 不考虑权限修饰符    Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes): 获取指定的构造方法, 不考虑权限修饰符 //
3. 获取成员方法们:    Method[] getMethods(): 获取所有 public 的成员方法    Method getMethod(String name, Class<?>... parameterTypes) : 获取指定的 public 成员方法Method[] getDeclaredMethods(): 获取所有的成员方法, 不考虑权限修饰符    Method getDeclaredMethod(String name, Class<?>... parameterTypes): 获取指定的成员方法, 不考虑权限修饰符 //
4. 获取Class对象代表的类的全类名    String getName(): 获取当前Class对象代表的类的全类名 //
5. 创建对象    T newInstance(): 使用当前类的空参构造, 创建一个对象
反射: 获取成员变量Field
java.lang.Class<T>类: 表示一个类的字节码对象, 其中包含该类中定义的内容    // 获取功能   
1. 获取成员变量们        Field[] getFields(): 获取所有 public 的成员变量        Field getField(String name): 获取指定名称的 public 的成员变量        Field[] getDeclaredFields(): 获取所有的成员变量, 不考虑权限修饰符        Field getDeclaredField(String name): 获取指定名称的成员变量, 不考虑权限修饰符
java.lang.reflect.Field: 表示一个成员变量    // 成员方法 String name;   Person p = new Person(); p2.name = "abc";    void set(Object obj, Object value): 设置指定对象的成员变量的值 field.set(p1, "abc")    Object get(Object obj): 获取指定对象的成员变量的值 field.get(p1)    void setAccessible(boolean flag): 传true时忽略访问权限修饰符的安全检查. 暴力反射 field.set

反射: 获取构造方法Constructor
java.lang.Class<T>类: 表示一个类的字节码对象, 其中包含该类中定义的内容    // 获取构造方法们   
Constructor<?>[] getConstructors(): 获取所有 public 的构造方法   
Constructor<T> getConstructor(Class<?>... parameterTypes): 获取指定的 public 构造方法   
Constructor<?>[] getDeclaredConstructors(): 获取所有的构造方法, 不考虑权限修饰符   
Constructor<T> getDeclaredConstructor(Class... parameterTypes): 获取指定的构造方法, 不 考虑权限修饰符    T newInstance(): 使用当前类的空参构造创建一个对象   
Constructor con = c.getConstructor(String.class, int.class);    con.newInstance("zhangsan", 18);    new Person("zhangsan", 18);        java.lang.reflect.Constructor<T>: 表示一个构造方法
// 成员方法   
T newInstance(Object... initargs): 使用当前构造方法传入参数, 创建对象    void setAccessible(boolean flag): 注意: 构造方法不能利用此方法忽略权限, 会抛异常
反射: 获取成员方法Method
java.lang.Class<T>类: 表示一个类的字节码对象, 其中包含该类中定义的内容    // 获取成员方法们:   
Method[] getMethods(): 获取所有 public 的成员方法   
Method getMethod(String name, Class<?>... parameterTypes) : 获取指定的 public 成员方法   
Method[] getDeclaredMethods(): 获取所有的成员方法, 不考虑权限修饰符   
Method getDeclaredMethod(String name, Class<?>... parameterTypes): 获取指定的成员方法, 不考虑权限修饰符   
java.lang.reflect.Method类: 表示一个成员方法    // 成员方法 Person p = new Person();   p.eat("adf", 123);      
Object invoke(Object obj, Object... args): 使用指定对象和指定参数值调用此方法   
String getName(): 获取方法名    void setAccessible(boolean flag): 传true时忽略访问权限修饰符的安全检查. 暴力反射
反射: 利用反射实现可以运行任意类的任意方法的框架案例
java.lang.Class<T>   
// 成员方法    ClassLoader getClassLoader(): 返回该类的类加载器     java.lang.ClassLoader: 类加载器 加载.class文件到内存的方法区中, 其他类型文件.properties   
// 成员方法    InputStream getResourceAsStream(String name): 读取相对于 out/production/模块名 目录中的 文件, 返回一个字节流
使用类加载器加载配置文件   

// 随便获取一个类的字节码对象    Class clazz = 类名.class;   
// 用字节码对象获取类加载器, 可加载bin目录中编译的文件    ClassLoader classLoader = clazz.getClassLoader();     
// 使用类加载器加载一个文件, 返回一个字节流    InputStream is = classLoader.getResourceAsStream("相对于src目录的相对路径");   
// 有了字节流, 就可以使用Properties的load(InputStream in)方法读取配置    Properties p = new Properties();    p.load(is);    String value = p.getProperty("key");
注解

注解: Annotation    JDK 1.5 引入. 也叫元数据, 是一种代码级别的说明    它可以声明在包, 类, 字段(成员变量), 方法, 局部变量, 方法参数等的前面, 用来对这些元素进行说明
注解: 说明程序的。给计算机看的 注释: 用文字描述程序的。给程序员看的
使用注解: @注解名称
作用分类:   

1. 编写文档: 通过代码里标识的注解生成文档         (生成API文档 @author @version @since @param @return)   
2. 代码分析: 通过代码里标识的注解对代码进行分析 (使用反射)        (JUnit提供的 @Test @Before @After)   
3. 编译检查: 通过代码里标识的注解让编译器能够实现基本的编译检查         (@Override @FunctionalInterface)
JDK中预定义的一些注解:   
@Override: 检测被该注解标注的方法是否是"重写"父类(接口)的   
@Deprecated: 该注解标注的内容,表示已过时   
@SuppressWarnings: 压制警告. 一般传递参数all  @SuppressWarnings("all")
自定义注解: 格式和本质
public interface 接口名 {}
自定义注解格式:关键字 @interface
    元注解    public @interface 注解名称 {        属性; (接口中的抽象方法)        属性;        属性;        ...            }
@注解名称     注解的本质:
    注解本质上就是一个接口,该接口默认继承Annotation接口    public interface MyAnno extends java.lang.annotation.Annotation {}

枚举:    enum, enumeration. JDK 1.5 引入    主要是用于定义一些"相关的"常量, 比如星期, 颜色, 用来进行区分
枚举定义方式: public enum 枚举名 {    枚举常量1, 枚举常量2, 枚举常量3; } 使用方式: 枚举名.常量名

自定义注解: 属性定义
属性:    接口中的"抽象方法"     属性的要求:   
1. 属性的"返回值类型"可以是以下类型:        基本数据类型(8种)        String        枚举        注解        以上类型的数组   
2. 定义了属性,在使用注解时, 需要"给属性赋值" (其实是抽象方法的返回值)        
     1. 属性使用 default 关键字指定默认值, 则可以不赋值        
     2. 如果只有一个名为"value"的属性需要赋值, 则 value 可以省略, 直接写值即可        
     3. 给数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}可以省略
自定义注解: 元注解
元注解:    用于描述注解的注解    常用元注解:   
@Target: 描述注解能够作用的位置        ElementType枚举的常用取值:            TYPE:可以作用于类上            METHOD:可以作用于方法上            FIELD:可以作用于成员变量上        示例: @Target(value = {ElementType.TYPE, ElementType.METHOD})   
@Retention: 描述注解被保留的阶段        RetentionPolicy枚举的取值:            SOURCE: 保留到源代码阶段            CLASS: 保留到类对象阶段            RUNTIME: 保留到运行时阶段        示例: @Retention(RetentionPolicy.RUNTIME):保留注解到class字节码文件中并被JVM读取到   
@Documented: 加上后, 当前注解会被抽取到api文档中   
@Inherited: 加上后, 当前注解会被子类继承
// 在自定义注解时, 可以使用以下元注解对我们自定义的注解进行约束

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
自定义注解: 解析注解
获取注解属性值的步骤:   
1. 获取注解定义位置的对象 (Class对象(类注解), Field对象(成员变量注解), Method对象(方法注解))   
2. 调用 ProAnno a = cls.getAnnotation(ProAnno.class) 方法获取注解对象   
3. 通过注解对象调用抽象方法获取属性值        
// 比如获取一个类上的注解    注解类型 注解变量名 = 被注解的类.class.getAnnotation(注解名.class);    数据类型 变量名 = 注解变量名.抽象方法();
ProAnno proAnno = Test.class.getAnnotation(ProAnno.class);   

String className = proAnno.className();   
String methodName = proAnno.methodName();














0 个回复

您需要登录后才可以回帖 登录 | 加入黑马