JAVA基础 : )

枚举格式:
public enum Season {
    SPRING,
    SUMMER,
    AUTUMN,
    WINTER
}
使用例:
    public static void main(String[] args) {
        method(Season.SPRING);
    }
    public static void method(Season season){
        System.out.println(season);
    }

注解:
java中已经存在的注解
@Override:表示方法的重写
@Deprecated:表示修饰的方法已过时
@SuppressWarnings("all"):压制警告
@Test
@Before 在Test之前运行,进行数据的初始化
@After 在Test之后运行,进行数据的还原
自定义注解---格式
public @interface 注解名称 {
    public 属性类型 属性名() default 默认值;
} // 属性类型包括:基本数据类型,String,Class,注解,枚举,以上类型的一维数组

与注解解析相关的接口
Annotation:注解的顶级接口
可以利用反射解析注解
Annotation[] getDeclaredAnnotations() 获取当前对象上使用的所有注解,返回注解数组
T getDeclaredAnnotation(Class<T> annotationClass) 根据注解类型获得对应注解对象
boolean isAnnotationPresent(Class<Annotion> annotationClass) 判断当前对象是否使用了指定的注解,如果使用了则返回true,否则false

元注解(了解)
可以写在注解上面的注解
@Target :指定注解能在哪里使用
@Retention :可以理解为保留时间(生命周期)

Target:
​ 作用:用来标识注解使用的位置,如果没有使用该注解标识,则自定义的注解可以使用在任意位置。
​ 可使用的值定义在ElementType枚举类中,常用值如下
- TYPE,类,接口
- FIELD, 成员变量
- METHOD, 成员方法
- PARAMETER, 方法参数
- CONSTRUCTOR, 构造方法
- LOCAL_VARIABLE, 局部变量

Retention:
​ 作用:用来标识注解的生命周期(有效范围)
​ 可使用的值定义在RetentionPolicy枚举类中,常用值如下
- SOURCE:注解只作用在源码阶段,生成的字节码文件中不存在
- CLASS:注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值
- RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段(开发常用)

单元测试
JUnit(注意:不能污染源数据)
编写测试方法:该方法必须是公共的无参数无返回值的非静态方法
在测试方法上使用@Test注解:标注该方法是一个测试方法
扩展点:
单元测试的相对路径是相对当前模块(不同情况下相对路径是会不断变化的)
在单元测试中,断言
// 参数一:当两个结果一样的时候,出现的提示消息
Assert.assertEquals("出错了",期望值,实际值);
JUnit常用注解
@Test
@Before 用来修饰实例方法,该方法会在每一个测试方法执行之前执行一次
@After 用来修饰实例方法,该方法会在每一个测试方法执行之后执行一次
@BeforeClass 用来静态修饰实例方法,该方法会在所有测试方法执行之前只执行一次
@AfterClass 用来静态修饰实例方法,该方法会在所有测试方法执行之后只执行一次
*开始执行的方法:初始化资源
*执行完之后的方法:释放资源

XML概述
是一种可扩展的标记性语言
标记语言:通过标签来描述数据的一门语言(标签有时我们也将其称之为元素)
可扩展:标签的名字是可以自己定义的
XML作用:
用于存储数据和传输数据
作为软件的配置文件
XML的其他组成
XML文件中可以定义注释信息:<!-注释内容-->
XML文件中可以存在以下特殊字符
&lt;    <小于
&gt;    >大于
&amp;    &和号
&apos;    '单引号
&quot;    "引号
XML文件中可以存在CDATA区:<![CDATA[于标识符冲突的符号*n]]>
XML文档约束-DTD的使用(了解)
引入本地dtd
    <!DOCTYPE 根元素名称 SYSTEM 'DTD文件路径'>
在xml文件内部引入
    <!DOCTYPE 根元素名称 [dtd文件内容]>
引入网络dtd
    <!DOCTYPE 根元素名称 PUBLIC"DTD文件名称""DTD文档的URL">
例:(dtd文件)
<!ELEMENT 书架 (书+)>
        <!ELEMENT 书 (书名,作者,售价)>
        <!ELEMENT 书名 (#PCDATA)>
        <!ELEMENT 作者 (#PCDATA)>
        <!ELEMENT 售价 (#PCDATA)>
(xml文件)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE 书架 SYSTEM 'DTDrain/dtdTest.dtd'>
<书架>
    <书>
        <书名>我推的孩子</书名>
        <作者>赤坂</作者>
        <售价>32.8</售价>
    </书>
</书架>

文档约束-schema(以xsd后缀的文件)
schema可以约束具体的数据类型,约束能力上更强大
schema本身也是一个xml文件,本身也受到其他约束文件的要求,所以编写的更加严谨
其他文件-约束>schema-约束>xml
例:
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" // xs类似一个变量代替需要反复调用的值
           targetNamespace="https://www.ye.cn/" // 名称(被约束的xml文件要用到这个名称)一般写成网址
           elementFormDefault="qualified"> // 固定格式(正确)
    <xs:element name="书架"> // 根标签
        <xs:complexType> // 这是一个复杂的标签
            <xs:sequence maxOccurs="unbounded"> // 顺序 + 无上限存储量(unbounded)
                <xs:element name="书"> // 标签
                    <xs:complexType> // 这是一个复杂的标签
                        <xs:sequence> // 顺序
                            <xs:element name="书名" type="xs:string"/>
                            <xs:element name="作者" type="xs:string"/>
                            <xs:element name="售价" type="xs:double"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

<?xml version="1.0" encoding="UTF-8" ?>
<书架 xmlns="https://www.ye.cn/">
    <书>
        <书名>我推的孩子</书名>
        <作者>赤坂</作者>
        <售价>88.6</售价>
    </书>
</书架>

Dom解析的文档对象模型是怎么样的
    Document对象:整个xml文档
    /*                Element对象:标签
    Node对象(节点)    Attribute对象:属性
    */                Text对象:文本内容(值)
Dom解析常用技术框架
Dom4J // 下载地址:https://dom4j.github.io/
Dom4J
SAXReader类
public SAXReader() 创建Dom4J的解析器对象
Document read(String url) 加载XML文件成为Document对象
Document类
Element getRootElements() 获取根元素对象
list<Element> elements() 得到当前元素下所有子元素
list<Element> elements(String name) 得到当前元素下指定名字的子元素返回集合
Element element(String name) 得到当前元素下指定名字的子元素返回集合
String getName() 得到元素名字
String getText() 得到文本
String attributeValue(String name) 通过属性名直接得到属性值
String elementText(子元素名) 得到指定名称的子元素的文本

例:
        // 创建集合存储解析到的信息
        ArrayList<Student> listStudent = new ArrayList<>();
        // 创建解析器对象
        SAXReader saxReader = new SAXReader();
        // 利用解析器去读取xml文件,并返回文档对象
        Document document = saxReader.read(new File("src\\rain\\fristXml.xml"));
        Element rootElement = document.getRootElement();
        List<Element> list = rootElement.elements();
        // 获取根标签的子标签
        for (Element element : list) {
            // 属性Id
            Attribute attribute = element.attribute("id");
            String Id = attribute.getText();
            // 标签名字
            Element name1 = element.element("name");
            String name = name1.getText();
            // 标签年龄
            Element age1 = element.element("age");
            String age = age1.getText();
            // 标签性别
            Element sex1 = element.element("sex");
            String sex = sex1.getText();

            listStudent.add(new Student(name,Integer.parseInt(age),sex,Id));
        }
        listStudent.forEach(System.out::println);
XPath介绍
XPath使用路径表达式来定位XML文档中的元素节点或属性节点
示例:
/元素/子元素/孙元素(绝对路径)
//子元素//孙元素
Document中与Xpath相关的API如下:
Node selectSingleNode("表达式") 获取符合表达式的唯一元素
List<Node> selectNodes("表达式") 获取符合表达式的元素集合
相对路径(从现在的自己节点开始的)
先得到根节点contactList
再采用相对路径获取下一级contact节点的name子节点并打印信息
./子元素/孙元素(是上面select方法的参数)
XPath:全文搜索
直接全文搜索所有的name元素并打印
//contact 找contact元素,无论元素在哪里
//contact/name 找contact元素,但name一定是contact的子节点
//contact//name contact无论在哪一种,name只要是contact子孙元素都可以找到

XPath:属性查找(!需要手动强转)
在全文中搜索属性,或者带属性的元素
//@属性名 查找属性对象,无论是哪个元素,只要有这个元素即可
//元素[@属性名] 查找元素对象,全文搜索指定元素名和属性名
//元素[@属性名='值'] 查找元素对象,全文搜索指定元素名和属性名,并且属性值相等

类加载器
public static ClassLoader getSystemClassLoadder() 获取系统类加载器
public InputStream getResourceAsStream(String name) 加载某一个资源文件
// 利用加载器去加载一个指定的文件
// 参数:文件的路径
// 返回值:字节流

日志
Logback快速入门
需求:导入Logback日志技术到项目中,用于记录系统的日志信息
分析:
1.在项目下新建文件夹lib,导入Logback的相关jar包到该文件夹下,并添加到项目依赖库中去
2.将Logback的核心配置文件logback.xml直接拷贝到src目录下(必须是src下)
// xml配置文件控制日志的输出位置等
3.在代码中获取日志的对象
public static final Logger LOGGER = loggerFactory.getLogger("类对象");// 类对象是当前类的字节码文件
// 日志级别
级别的程度以此是TRACE<DEBUG<INFO<WARN<ERROR;默认级别是debug(忽略大小写),对应其方法
作用:用于控制系统中哪些日志级别是可以输出的,只输出级别不低于设定级别的日志信息
all和off分别是打开全部日志信息,及关闭全部日志信息
具体在<root level="INFO" >标签的level属性中设置日志级别

4.。使用日志对象的方法记录系统的日志信息
代码实例:
public class LoggerDemo {
    // 获取日志对象
    public static final Logger LOGGER = LoggerFacory.getLogger("LoggerDemo.class");
    
    public static void main(String[] args) {
    // 就可以记录用户的操作日志
    // 假设用户调用了某个方法
    LOGGER.info("用户于**时刻登录了");
    // 此时控制台就会跳出日志并且在配置文件规定好的路径里就会有相应的log文件 
    }
}

获取class对象的三种方式
1源代码阶段用 Class.forName("全类名"); // 全类名:包名.类名
最常用的
2加载阶段用 类名.class
更多用作参数传递
例:synchronized(this.class){}
3运行阶段用 对象.getClass
当我们有了这个对象时才可以使用

利用反射获取构造方法(形参也是对应的字节码文件)
Constructor<?> clazz.getConstructor(); // 获取一个 公共 的空参的构造方法
Constructor<?> clazz.getConstructor(?.class); // 获取一个 公共 的有参的构造方法
Constructor<?> clazz.getDeclaredConstructor(?.class); // 获取一个构造方法(包括私有的)
Constructor<?>[] clazz.getDeclaredConstructors();// 获取所有构造方法(包括私有的)
Constructor<?>[] clazz.getConstructors(); // 获取所有公共的构造方法
int getModifiers; // 获取权限修饰符的值 
// 暴力反射:表示临时取消权限检验(用于创建私有修饰符修饰的构造方法的对象)
        constructor.setAccessible(true);
// 利用反射的构造方法创建对象
Student o = (Student) constructor.newInstance();

利用反射获取成员变量(形参是字符串)
Class类中用于获取成员变量的方法
Field[] getFields():返回所有公共成员对象的数组
Field[] getDeclaredFields():返回所有成员变量的数组
Field getField(String name):返回单个公共成员变量对象
Field getDeclaredField(String name):返回单个成员变量对象

getType(); 获取成员变量的数据类型
int getModifiers; // 获取权限修饰符的值 
Field类中用于创建对象的方法
void set(Object obj,Object value):赋值(无论什么数据类型修改一律用字符串)
Object get(Object obj)获取值_

利用反射获取成员方法
Method[] getMethods():返回所有公共成员方法对象的数组,包括继承的
Method[] getDeclaredMethods():返回所有成员方法对象的数组,不包括继承的
Method getMethod(String name,Class<?>...parameterTypes):返回单个成员方法对象(形参二就是形参数据类型的.class文件)
Method getDeclaredMethod(String name,Class<?>...parameterTypes):返回单个成员方法对象

Method类中用于创建对象的方法
Object invoke(Object obj,Object...args):运行方法
参数一:用obj方法调用该方法
参数二:调用方法的传递的参数(如果没有就不写)
返回值:方法的返回值(如果没有就不写)

反射的用法:
例1:保存数据
public static void main(String[] args) throws IllegalAccessException, IOException {
        Student student = new Student("星野爱",18,49.5,170);
        Teacher mother = new Teacher("福利姬", 10000);
        saveData(student);
        saveData(mother);
    }

    private static void saveData(Object object) throws IllegalAccessException, IOException {
        Class<?> clazz = object.getClass();
        BufferedWriter bw = new BufferedWriter(new FileWriter("src\\a.txt",true));
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            declaredField.setAccessible(true);
            String name = declaredField.getName();
            Object o = declaredField.get(object);
            bw.write(name + "=" + o);
            bw.newLine();
        }
        bw.close();
    }
例2:跟配置文件结合动态创建
反射可以跟配置文件结合的方式,动态的创建对象,并调用方法
Properties pops = new Properties();
        BufferedReader br = new BufferedReader(new FileReader("properties.properties"));
        pops.load(br);

        String objectType = pops.getProperty("objectType");
        String method = pops.getProperty("method");
        System.out.println(objectType);
        System.out.println(method);

        Class<?> clazz = Class.forName(objectType);
        Constructor<?> declaredConstructor = clazz.getDeclaredConstructor();
        declaredConstructor.setAccessible(true);
        Object o = declaredConstructor.newInstance();
        Method declaredMethod = clazz.getDeclaredMethod(method);
        declaredMethod.setAccessible(true);
        declaredMethod.invoke(o);

为什么需要代理?
代理可以五侵入式的给对象增强其他的功能
调用者->代理->对象
代理长什么样
代理里面就是对象要被代理的方法
java通过什么来保证代理的样子
通过接口保证,后面的对象和代理需要实现同一个接口
接口中就是被代理的所有方法

如何为java对象创建一个代理对象?
java.lang.reflect.Proxy类:提供了为对象产生代理的方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)
参数一:用于指定哪个类加载器,去加载生成的代理类
参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法
参数三:用来指定生成的代理对象要干什么事情
例:
public class ProxyUtil {
    /*
     * 需求:外面的人想要大明星唱一首歌
     * 1.获取代理的对象
     * 代理对象 = ProxyUtil.createProxy(大明星对象);
     * 2.再调用代理的唱歌方法
     * 代理对象。唱歌的方法("B小町")
     * */
    public static Star createProxy(BigStart bigStart) {
        /*java.lang.reflect.Proxy类:提供了对象产生代理对象的方法:
        *
        * public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)
            参数一:用于指定哪个类加载器,去加载生成的代理类
            参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法
            参数三:用来指定生成的代理对象要干什么事情
        *
        *
        * */
        Star s = (Star) Proxy.newProxyInstance(
                ProxyUtil.class.getClassLoader(), // 用于指定哪个类加载器,去加载生成的代理类
                new Class[]{Star.class}, // 参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法
                new InvocationHandler() { // 参数三:用来指定生成的代理对象要干什么事情
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        /*参数一:代理的对象(一般不用)
                        *参数二:要运行的方法
                        * 参数三:方法运行要传递的实参
                        * */
                        switch (method.getName()) {
                            case "sing":
                                System.out.println("准备话筒");
                                break;
                            case "dance":
                                System.out.println("申请巨蛋");
                                break;
                        }
                        // 调用明星对象的方法
                        return method.invoke(bigStart, args); // 如果有返回值就返回
                    }
                }
        );
        return s; // 返回接口的实现类
    }
}
测试类代码:
public class Test {
    public static void main(String[] args) {
        BigStart bigStart = new BigStart("星野爱");
        Star proxy = ProxyUtil.createProxy(bigStart);
        String result = proxy.sing("熙熙攘攘,我们的城市");
        System.out.println(result);
        proxy.dance();
    }
}

网络编程:
计算机跟计算机之间通过网络进行数据传输
常见的软件架构有哪些?
CS/BS
通信的软件架构CS\BS的各有什么区别和优缺点
CS:客户端服务端模式需要开发客户端
BS:浏览器服务端模式不需要开发客户端
CS:适合定制专业化的办公软件如:IDEA、网游
BS:适合移动互联网应用,可以在任何地方随时访问的系统

特殊IP地址
127.0.0.1,也可以是loclhost:是回送地址也称本地回环地址,也称本机IP,永远只会寻找当前所在本机
组播
组播地址:224.0.0.0~239.255.255.255
其中224.0.0.0~224.0.0.255为预留的组播组播地址
广播
255.255.255.255

TCP协议:
发送数据例:
//1.创建Socket对象
        //细节:在创建对象的同时会连接服务端
        //如果连不上,代码会报错
        Socket socket = new Socket("127.0.0.1",10086);
        // 从连接通道中获取输出流
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("我".getBytes());
// 细节:
    // 写出结束标记
    socket.shutdownOutput(); // 结束标记

        socket.close();
接收数据例:
// 创建对象ServerSocket
        ServerSocket serverSocket = new ServerSocket(10086);
        // 监听客户端的连接
        Socket socket = serverSocket.accept();// 阻塞
        // 从连接通道中获取输入流读取数据
        InputStream inputStream = socket.getInputStream();
        int len;
        byte[] bytes = new byte[1024];
        while ((len = inputStream.read(bytes)) != -1) {
            System.out.println(new String(bytes,0,len));
        }
// 细节:
    // read方法会从连接通道中读取数据
    // 但是,需要有一个结束标记,此处的循环才会停止
    // 否则,程序就会一直停在read方法这里,等待读取下面的数据
    // 之前停止可能是因为用户关闭了通道
        serverSocket.close();
// 细节2:
如果接收端用了buffered等缓冲流,则需要调用缓冲流的刷新方法清空缓冲池(bufferedWriter.flush();)

UDP协议:
发送数据例:
        // 创建DatagramSocket对象(快递公司)
        // 绑定端口,以后我们就是通过这个端口往外发送
        // 空参:所有可用的端口中随机一个进行使用
        // 有参:指定端口号进行绑定
        DatagramSocket datagramSocket = new DatagramSocket();
        // 打包数据
        String str = "阿米诺斯";
        byte[] bytes = str.getBytes();
        InetAddress address = InetAddress.getByName("127.0.0.1");
        int port = 10086;
        DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port);
        // 3.发送数据
        datagramSocket.send(dp);
        // 4.释放资源
        datagramSocket.close();
接收数据例:
// 接收数据
        // 1.创建DatagramSocket对象(快递公司)
        // 细节:在接收的时候,一定要绑定端口
        // 而且绑定的端口一定要跟发送的端口一致
        DatagramSocket ds = new DatagramSocket(10086);
        // 2.接收数据包
        byte[] bytes = new byte[1024];
        DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
        // 该方法是阻塞的
        ds.receive(dp);
        // 3.解析数据包
        byte[] data = dp.getData();
        int length = dp.getLength();
        InetAddress address = dp.getAddress();// 发送者的IP地址
        int port = dp.getPort();// 发送者的端口号
        System.out.println(new String(data,0,length));
        System.out.println(address + "端口号:" + port);
        ds.close();

线程池代码实现:
Executors:线程池的工具类通过调用方法返回不同类型的线程池对象
public static ExecutorService newCachedThreaadPool() 创建一个没有上限的线程池
public static ExecutorService newFixedThreadPool(int nThreaads) 创建有上限的线程池
常见方法:
submit()
shutdown() 销毁线程池 // 一般不用

自定义线程池:
/*        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor
        参数一:核心线程数量 不能小于0
        参数二:最大线程数 不能小于0,最大数量 >= 核心线程数量
        参数三:空闲线程最大存活时间 不能小于0
        参数四:时间单位 用TimeUnit指定
        参数五:任务队列 不能为null
        参数六:创建线程工厂 不能为null
        参数七:任务的拒绝策略 不能为null*/
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                10,
                17,
                60,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(10), // 如果不想指定上限就用链表
                Executors.defaultThreadFactory(), // 线程池如何去获取到一个线程
                new ThreadPoolExecutor.AbortPolicy() // 丢弃任务并抛出异常
        );
        threadPoolExecutor.submit();

线程池多大合适呢?
cpu密集型运算=最大并行数+1
I/O密集型运算=最大并行数*期望cpu利用率*(总时间(cpu计算时间+等待时间)/cpu计算时间)
例:
10核16线程
16*100%*(100%/50%)=32
总时间(cpu计算时间+等待时间)/cpu计算时间)可以用tread dump获取

多线程
并发:在同一时刻,有多个指令在单个cpu上交替执行
并行:在同一时刻,有多个指令在多个cpu上同时执行

多线程的第三种实现方式:(利用Callable接口和Future接口方式实现)
特点:可以获取到多线程运行结果
1.创建一个类MyCallable实现Callable接口
2.重写call(是有返回值的,表示多线程的运行结果)
3.创建Mycallable的对象(表示多线程要执行的任务)
4.创建FutureTask的对象(作用管理多线程运行的结果)
5.创建Thread类的对象,并启动(表示线程)

Thread常见的成员方法
String getName() 返回此线程名称
void setName() 设置线程的名字(构造方法也可以设置名字)
static Thread currentThread() 获取当前线程的对象
static void sleep(long time) 让线程休眠指定的时间,单位为毫秒
setPriority(int newPriority) 设置线程的优先级1-10默认5
final int getPriority() 获取线程的优先级
final void setDaemon(boolean on) 设置为守护线程
public static void yield() 出让线程/礼让线程
public static void join() 插入线程/插队线程

关键字synchronized(锁对象)
被synchronized修饰的代码叫同步代码块,被synchronized修饰的方法叫同步方法
注意:锁对象是唯一的,一般是当前类的字节码文件:(当前类名.class)
同步方法
同步方法锁对象不能自己指定:
非静态:this
静态:当前类的字节码文件对象(当前类名.class)

生产者和消费者(常见方法)
用锁调用方法,例:
Desk.lock.wait();// 让当前线程跟锁进行绑定
Desk.lock.notifyAll();// 唤醒这把锁绑定的所有线程

阻塞队列例:
ArrayBlockingQueue<String> abq = new ArrayBlockingQueue<>(1);// 1代表数组最大长度
常见方法:
take(); // 取出对象
put();// 放入对象

void wait() 当前线程等待,直到被其他线程唤醒
void notify() 随机唤醒单个线程
void notifyAll() 唤醒所有线程

properties集合
properties是一个双列集合,拥有Map集合所有的特点。
重点:有一些特有的方法,可以把集合中的数据,按照键值对的形式写到配置文件中。
也可以把配置文件中的数据,读取到集合中来。
特有方法:
load(Reader reader) 把properties文件中的数据读取到集合中
store(OutputStream out, String comments) 把properties集合写到properties文件中
store(Writer writer, String comments) comments表示在properties文件开头写入的注释

获取一个0.0-0.1之间的随机数
double number = Math.random();
数组的二分查找法
int index = arrays.binarySearch(数组,要查找的数); // 返回-(负)插入点-1

打印流有几种?各有什么特点?
有字节打印流和字符打印流
打印流不操作数据源,只能操作目的地
字节打印流:默认自动刷新,特有的println自动换行
字符打印流:自动刷新需要开启,特有的println自动换行

字符打印流:
PrintWriter(Writer/File/String) 关联字符输出流/文件/文件路径
字符流底层有缓冲区,想要自动刷新需要开启

字节打印流:
构造方法
public PrintStream(OutputStream/File/String) 关联字节输出流/文件/文件路径
public PrintStream(String fileName, Charset charset)指定字符编码
public PrintStream(OutputStreamout, boolean autoFlush)自动刷新
public PrintStream(OutputStream out, boolean autoFlush, String encoding)指定字符编码且自动刷新
成员方法:
public void write(int b) 常规方法:规则跟之前一样,将指定的字节写出
public void println(Xxx xx) 特有方法:打印任意数据,自动刷新,自动换行
public void print(Xxx xx) 特有方法:打印任意数据,不换行
public void printf(String format, Object...args)  特有方法:带有占位符的打印语句,不换行

序列化流/反序列化流的细节汇总
①使用序列化流将对象写到文件时,需要让Javabean类实现Serializable接口。
否则,会出现NotSerializableException异常
②序列化流写到文件中的数据是不能修改的,一旦修改就无法再次读回来了
③ 序列化对象后,修改了Javabean类,再次反序列化,会不会有问题?
会出问题,会抛出InvalidClassException异常解决方案:给Javabean类添加serialversionUID (序列号、版本号)
④如果一个对象中的某个成员变量的值不想被序列化,又该如何实现呢?
解决方案:给该成员变量加transient关键字修饰,该关键字标记的成员变量不参与序列化过程
5.如果一次要写多个对象可以把多个对象放进集合中,直接写出集合就可以了
5.1解决方案:try catch 
例: while (true) {
                try {
                    Student student = (Student) ois.readObject();
                    students.add(student);
                } catch (EOFException e) {
                    break;
                }
序列化流/对象操作输出流 // 把一个对象写到本地文件中
构造方法:
public ObjectOutputStream(OutputStream out) 把基本流变成高级流
    注意:使用对象输出流将对象保存到文件时会出现NotSerializableException异常
    解决方案:需要让Javabean类实现Serializable接口
成员方法:
public final void writeObject(Object obj) 把对象序列化(写出)到文件中去

反序列化流/对象操作输入流
构造方法:
public ObjectInputStream(InputStream In) 把基本流变成高级流
    注意:在使用反序列化流的时候,对象内部不能发生改变,如果要升级,那么对象隐藏的版本号就会发生变化,而与反序列化流发生冲突
    解决方案:自定义对象的版本号、用idea自带提示生成
        注意:因为版本号是根据类的内容计算的,要最后写
        注意:如果不想让隐私数据可以被反序列化到本地文件中,需要在成员变量前加上  transient:瞬态关键字  // 作用:不会把当前属性序列化到本地文件中
单例:pribate static final long seriaVersionUID = 1L; // 只有这一种格式!!!

成员方法:
public Object readObject() // 把序列化到本地文件中的对象,读取到程序中来
字节输入/出输出缓冲流
BufferInputStream(InputStream is);
BufferOutputStream(OutputStream os);
字符输入/出缓冲流
BufferedReader(Reader r) // 把基本流转换为高级流
BufferedWriter(Writer w) // 把基本流转换为高级流
字符缓冲流的方法
readLine(); // 一次读取一行
newLine(); // 跨平台的换行
FileReader fr = new FileReader(file, Charset.forName("GBK")); // 按照GBK的方式读取

FileInputStream书写细节
1.创建字节输入流对象
细节:如果文件不存在,就直接报错
2.读取数据
细节1:一次读一个字节,读出来的是数据在ASCII上对应的数字
细节2:读到文件末尾了,read方法返回-1。
    注意:read();方法和迭代器类似,每调用一次指针就会后移,具体见例
3.释放资源
细节:每次使用完流之后都要释放资源
例:        FileInputStream fis =new FileInputStream("a.txt");
        int b;
        while ((b=fis.read()) != -1){ //  一次读取只调用一次read方法
            System.out.print((char) b);
        }
        fis.close();

FileOutputStream
1.创建字节输出流对象
细节1:参数是字符串表示的路径或者File对象都是可以的
细节2:如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的
细节3:如果文件已经存在,则会清空文件(在创建对象时写入第二个参数为true就会打开续写开关)
2.写数据
细节:write方法的参数是整数,但是实际上写到本地文件中的是整数在ASCII上对应的字符
write(byte[] b, int off, int len); b:数组 off:起始索引 len:个数
win换行是 \r\n
lin换行是 \n
mac换行是 \r
3.释放资源
细节:每次使用完流之后都要释放资源
例:
        FileOutputStream fos = new FileOutputStream("a.txt",true);
        fos.write("阿米诺斯\r\n".getBytes());
        fos.close();

字符集
1,在计算机中,任意数据都是以二进制的形式来存储的
2,计算机中最小的存储单元是一个字节
3. ASCII字符集中,一个英文占一个字节
4,简体中文版Windows,默认使用GBK字符集
5, GBK字符集完全兼容ASCII字符集
一个中文占两个字节,二进制高位字节的第一位是1
一个英文占一个字节,二进制第一位是0

1. Unicode字符集的UTF-8编码格式
一个英文占一个字节,二进制第一位是0,转成十进制是正数
一个中文占三个字节,二进制第一位是1,第一个字节转成十进制是负数

Java中编码的方法
getBytes(); // 使用默认方式进行编码
getBytes("GBK"); // 使用指定GBK方式进行编码

Java中解码的方法
String(byte[] bytes); // 使用默认方式进行解码
String(byte[] bytes, "GBK") // 使用指定GBK方式进行解码

File
构造方法:
File(String pathname) // 根据文件路径创建文件对象
File(String pathname, String child)// 根据父路径名字字符串和子路径字符串创建文件对象
File(File path, String child)// 根据父路径对应文件和子路径字符串创建文件对象
方法:
isFile() // 是文件吗
isDirectory() // 是文件夹吗
exists() // 存在吗
length() // 返回文件大小(字节)
getAbsolutePath() // 返回文件的绝对路径
getPath() // 返回定义文件时使用的路径
getName() // 返回文件的名称 带后缀
lastModified() // 返回文件最后的修改时间 毫秒值

createNewFile() // 根据对象的路径创建一个新的空的文件
mkdirs() // 根据调用者的路径创建一个新的多级文件夹
delete() // 删除文件,空文件夹
删除的细节:
如果删除的是文件,则直接删除,不走回收站
如果删除的是空文件夹,则直接删除,不走回收站
如果删除的是有内容的文件夹,则删除失败

File获取并遍历
listRoots() // 列出可用的文件系统根
list() // 获取当前该路径下的所有内容
list(FilennameFilter filter) // 利用文件名过滤器获取该路径下所有内容
listFiles() // 获取当前该路径下的所有内容的绝对路径
listFiles(FileFilter filter) // 利用文件名过滤器获取该路径下所有内容
listFiles(FilennameFilter filter) // 利用文件名过滤器获取该路径下所有内容

方法引用
我的总结:在形参是实现类的情况下,用 类名::方法 代替抽象方法的方法体
方法引用就是把已经存在的方法拿过来用,当作函数式接口中抽象方法的方法体
::是方法引用符
方法引用时需要满足:
有函数式接口
被引用的方法已经存在
被引用的方法的形参和返回值需要跟抽象方法保持一致
被引用的方法的功能要满足当前的需求

Stream流创建
Stream.Builder(); // 返回一个动态的流
streamBuilder.add("a"); // 添加一个元素
streamBuilder.build(); // 返回创建的流
Stream.generate(() -> "string"); // 创建一个无限流(危险,通常用limit限制生成的个数)
Stream.iterate(0, n -> n + 2).limit(5); // 生成一个有界的等差数列
Stream.iterate(0, n -> n <= 10, n -> n + 2); // 生成一个有界的等差数列
stream.parallel(); // 创建一个并行流
Stream.of(T...t) // 创建一个Stream流

// 通过File分别读取每一行返回一个流
Path path = Paths.get("file.txt");
try(Stream<String> lines = Files.lines(path)) {
    lines.forEach(System.out::println);
} catch (IOException e) {
    e.getStackTrace();
}

Stream流的中间方法
filter() 过滤
limit() 获取前几个元素
skip(long n) 跳过前几个元素
distinct() 元素去重,依赖哈希值和equals方法
concat() 合并a和b两个流
map() 转换流中的数据类型(映射)
flatMap(Collection::stream) 将多层数据(集合的嵌套)转换为单层流,底层是先分别取出第二层的集合转换为流并返回,而flatMap负责合并
flatMap(people -> people.stream().map(Person::getName)) 将多层数据转换为单层流并映射
mapToInt 转换为数值流(Long\double也行)
sorted() 排序(参数是Compareable接口)

Stream流的终结方法
forEach() // 遍历
forEachOrdered() // 多线程顺序遍历
count() // 统计个数
max() // 最大值
sum()
average()
toArray() // 收集流中的数据,放到数组中
collect() // 收集流中的数据,放到集合中
collect(Collectors.groupingBy(Person::getAge)); // 把流中的数据按照年龄进行分组
collect(Collectors.partitioningBy(person -> person.getAge > 18)); // 分区
collect(Collectors.joining(",")); // 拼接
collect(Collectors.summarizingInt(Person::getAge); // 统计 
anyMatch(person -> person.getAge > 18); // 判断流中是否存在满足条件的值
noneMatch(person -> person.getAge > 18); // 与上一条相反
allMatch(person -> person.getAge > 18); // 所有元素都满足条件才返回true
findFirst();
findAny();
reduce(0, (a, b) -> a + b); // 聚合
reduce("", (a, b) -> a + b + ","); // 聚合


TreeMap
红黑树结构
由键决定特性:不重复、无索引、可排序(对键进行排序)
代码书写两种规则
实现Comparable接口,指定比较规则
创建集合时传递Comparator比较器对象,指定比较规则(两种都写了以第二种为准)

(String string).compareTo(String string); // 把字符按照ASCII码表排序

Map的遍历方式(lambda表达式)
degault void forEach(BiConsumer<? super K, ? super V> action) 结合lambda遍历map集合
例:
        Map<String, String> map = new HashMap<>();
        map.put("黄泉", "我为逝者哀哭");
        map.put("星", "规则就是用来打破的");
        map.put("景元", "斩无赦");
        // 用拉姆达表达式遍历
        map.forEach((string, string2) -> System.out.println(string + ":" + string2));

Map的常见的API
Map是双列集合的顶层接口,它的功能是全部双列集合都可以继承使用的
V put(K key,V value) 添加/覆盖元素
V remove(Object key) 根据键删除键值对元素
void clear() 移除所有的键值对元素
boolean containsKey(Object Key) 判断集合是否包含指定的键
boolean containsValue(Object value) 判断集合是否包含指定的值
boolean isEmpty() 判断集合是否为空
int size() 集合的长度,也就是集合中键值对的个数
merge()
gradeList.forEach(integer -> countGrade.merge(integer, 1, Integer::sum));

TreeSet底层用的是红黑树,不需要重写hash值和equals方法,而是通过比较器来判断的
注意:如果想用默认的比较规则直接用 this.对象.compareTo(o); 将返回默认比较规则返回的值
1:javaBean类实现Comparable<E> 接口
例:    @Override
    public int compareTo(Student o) {
        int i = Integer.parseInt(this.grade) - Integer.parseInt(o.getGrade());
        i = i == 0 ? -1 : i;
        return i;
    }
返回值:
负数:认为要添加的元素是小的,存左边
正数:认为要添加的元素是大的,存右边
0:认为要添加的元素已存在,舍弃
2:在创建时传递一个比较器(推荐)

数据结构(树)
度:每一个节点的子节点数量
树高:树的总层数
根节点:最顶层的节点
左子节点:左下方的节点
右子节点:右下方的节点
根节点的左子树:蓝色虚线
根节点的右子树:绿色虚线
数据结构
栈:后进先出,先进后出
数据进入栈模型的过程称为:压/进栈
数据离开栈模型的过程称为:弹/出栈
队列:先进先出,后进后出
数据从后端进入队列模型的过程称为:入队列
数据从前端离开队列模型的过程称为出队列

集合名.foreach(new Consumer<E>());// 拉姆达了lambda表达式遍历集合

增强for、lambda在仅仅想遍历的时候使用,在遍历的过程中想删除元素,请使用迭代器
在遍历时需要添加元素,请使用列表迭代器list.Iterator
如果在遍历时想操作索引,可以使用普通for
1.迭代器在遍历集合的时候是不依赖索引的
2.三个方法
        // 创建一个迭代器对象
        Iterator<String> iterator = c.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
3.迭代器的四个细节
如果当前位置没有元素,还要强行获取,会报错
迭代器遍历完毕,指针不会复位
循环中只能用一次next方法
迭代器遍历时,不能用集合的方法进行增加或者删除,请使用迭代器的方法
Collection是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的
boolean add(E e) 把给定的对象添加到当前集合中
void clear()清空集合中所有的元素
boolean remove(E e) 把给定的对象在当前集合中删除
boolean contains(Object obj) 判断当前集合中是否包含给定的对象
boolean isEmpty() 判断当前集合是否为空
int size() 返回集合中元素的个数/集合的长度
Collection
集合Collection体系结构
List系列集合:添加的元素是有序、可重复、有索引
Set系列集合:添加的元素是无序、不重复、无索引
contains方法:如果集合中存储的是自定义对象,也想通过contains方法来判断是否包含,那么在javabean类中,一定要重写equals方法
插值查找 (前提是数据尽可能的分布均匀)
公式:
mid = min + (key-arr[min])/(arr[max]-arr[min])*(max-min)
二分查找/折半查找(前提是数组中的数据是有序的)
1.min和max表示当前要查找的范围
2.mid实在min和max中间的
3.如果要查找的元素在mid的左边,缩小范围时,min不变,max等于mid减1
4.如果要查找的元素在mid的右边,缩小范围时,max不变,min等于mid加1
泛型
1:哪里定义泛型?
泛型类:在类名后面定义泛型,创建该类对象的时候,确定类型
泛型方法:在修饰符的后面定义方法,调用该方法的时候,确定类型
泛型接口:在接口名后面定义泛型,实现类确定类型,实现类延续泛型
2:泛型的继承和通配符
泛型不具备继承性,但是数据具备继承性
泛型的通配符:?
?extends E
? super E
3:使用场景
定义类、方法、接口的时候,如果类型不确定,就可以定义泛型
如果类型不确定,但是能知道是哪个继承体系中的,就可以使用泛型的通配符
Integer(int对象)
public static String toBinaryString(int i) 得到二进制
public static String toOctalString(int i) 得到八进制
public static String toHexString(int i) 得到十六进制
public static int parseInt(String s) 将字符串类型的整数转成int类型的整数
时间
String birth = "2005年07月24日";
SimpleDateFormat regex = new SimpleDateFormat("yy年MM月dd日");
Date parse = regex.parse(birth);
long time = parse.getTime();
long now = System.currentTimeMillis();// 获取当前时间的毫秒值
long between = now - time;
System.out.println(between / 1000 / 3600 / 24);

ZonedDateTime now = ZonedDateTime.now();
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss E a");
String format = dateTimeFormatter.format(now);
System.out.println(format);
// 计算时间差
LocalDateTime now = LocalDateTime.now();
LocalDateTime birth = LocalDateTime.of(2005, 7, 24, 0, 0, 0);
long between = ChronoUnit.YEARS.between(birth, now);
右移>>代表除以2
1.Calenddar表示什么?
表示一个时间的日历对象
2. 如何获取对象
用静态方法getInstance获取对象
3.常见方法
setXxx:修改
get:Xxx:获取
add:在原有的基础上进行增加或减少
4.细节点:
日历中月份的范围:0-11
日历中星期的特点:星期日是一周中的第一天
爬虫
1.获取正则表达式的对象
Pattern p = Pattern.compile("正则表达式");
2.获取文本匹配器的对象
// 拿着m去读str,找符合p规则的子串
Matcher m = p.matcher(str);
3.利用循环获取
while(m.find()){
    System.out.println(m.group());
}
String regex1 = "(?i)java(?=8|11|17)";
// ?理解为前面的数据java
// =表示在java后面要跟随的数据
// 但是在获取的时候,只获取前半部分
String regex2 = "(?i)java(8|11|17)";
String regex2 = "(?i)java(?:8|11|17)";
// 获取的时候,获取全部
String regex2 = "(?i)java(?!8|11|17)";
// 获取的时候,获取除了符合条件的值
只写+和*表示贪婪匹配
+? 非贪婪匹配
+* 非贪婪爬取
正则表达式在字符串中的使用
matches(String regex) 判断字符串是否满足正则表达式的规则
replaceAll(String regex,String newStr) 按照正则表达式的规则进行替换
split(String regex) 切割字符串
正则表达式分组(括号括起来的内容)
1.正则表达式中分组有两种
捕获分组、非捕获分组
2.捕获分组(默认)
可以获取每组中的内容反复使用 内部\\?外部$?
3.组号的特点
从1开始,连续不间断,以左括号为基准,最左边的是第一组
4.非捕获分组
分组之后不需要再使用本组数据,仅仅把数据括起来,不占组号
(?:)(?=)(?!)都是非捕获分组
正则表达式:(插件:any-rule)
字符类 
[abc] a、b 或 c(简单类) 
[^abc] 任何字符,除了 a、b 或 c(否定) 
[a-zA-Z] a 到 z 或 A 到 Z,两头的字母包括在内(范围) 
[a-d[m-p]] a 到 d 或 m 到 p:[a-dm-p](并集) 
[a-z&&[def]] d、e 或 f(交集) 
[a-z&&[^bc]] a 到 z,除了 b 和 c:[ad-z](减去) 
[a-z&&[^m-p]] a 到 z,而非 m 到 p:[a-lq-z](减去) 
预定义字符类 
. 任何字符(与行结束符可能匹配也可能不匹配) 
\d 数字:[0-9] 
\D 非数字: [^0-9] 
\s 空白字符:[ \t\n\x0B\f\r] 
\S 非空白字符:[^\s] 
\w 单词字符:[a-zA-Z‘下划线’0-9] 
\W 非单词字符:[^\w] 
Greedy 数量词 
X? X,一次或一次也没有 
X* X,零次或多次 
X+ X,一次或多次 
X{n} X,恰好 n 次 
X{n,} X,至少 n 次 
X{n,m} X,至少 n 次,但是不超过 m 次 
反斜线、转义和引用 
反斜线字符 ('\') 用于引用转义构造,如上表所定义的,同时还用于引用其他将被解释为非转义构造的字符。因此,表达式 \\ 与单个反斜线匹配,而 \{ 与左括号匹配
(?i)忽略后面字符的大小写  (?i)abc
a((?i)b)c只忽略b的大小写
BigDecimal
BigDecimal表示一个大小数
如何获取BigDecimal的对象?
BigDecimal bd1 = BigDecimal.valueOf(10);
BigDecimal bd1 = new BigDecimal("0.01");
// 细节:
1.如果要表示的数字不大,没有超出double的取值范围,建议使用静态方法
2.如果要表示的数字比较大,超出了double的取值范围,建议使用构造方法
3.如果我们传递的是0-10之间的整数,包含0,包含10,那么方法会返回已经创建好的对象,不会重新new
方法名:
public static BigDecimal valueOf(double val) // 获取对象
public BigDecimal add(BigDecimal val) // 加法
public BigDecimal subtract(BigDecimal val) // 减法
public BigDecimal multiply(BigDecimal val) // 乘法
public BigDecimal divide(BigDecimal val) // 除法
public BigDecimal divide(BigDecimal val,精确几位,舍入模式) // 除法
// 舍入模式例:RoundingMode.HALF-UP 四舍五入
BigIntger表示一个大整数。
如何获取BigIntger的对象?
BigIntger b1 = BigIntger.valueof(0.1);
// 此方法会自动创建-16~16之间的对象,节省内存
BigIntger b1 = new BigIntger("整数");
常见操作:
加:add
减:subtract
乘:multiply
除:divide、divideAndRemainder// 获取商和余数,返回类型是一个长度为2的数组
比较:equals、max、min
次幂:pow
转成整数:intValue、longValue
工具类Objects:
Objects.equals(对象一,对象二);// 此方法解决了对象地址值为null时报错的问题
细节:
1.方法的底层会判断对象一是否为null,如果为null,直接返回false
2.如果对象一不为null,那么就利用对象一再次调用equals方法
3.如果对象是子类类型,所以最终还是会调用对象一中的equals方法
// 如果equals方法没有重写,比较地址值,如果重写了,就比较属性值
isNull(object obj)判断是否为null,为null返回true
nonNull(object obj)判断是否为null,为null返回false
object:
如果我们打印一个对象,想要看到属性值的话,只要重写toString方法就好了
克隆对象细节:
方法在底层帮我们创建一个对象,并把对象中的基本数据和引用数据的地址值拷贝过去
书写细节:(浅克隆)
1.重写Object中的clone方法
2.让javaBean类实现Cloneable接口(标志接口,表示当前类可被克隆)
3.创建对象并调用clone就可以了
// 深克隆需要手动写或用第三方软件(gson)写
1。创建对象2.新建引用数据类型的对象3.复制并把新的引用数据类型地址赋给给克隆的对象
GUI组件:
JFrame最外层的界面、窗体
JFrame是一个父类,子类继承(extends)它代表某些功能的窗口,比如:
登录窗口
让相关代码全部写在这个JavaBean内,在构造方法中写入关于创建/设置/可使等一系列初始化this(调用者的地址值).~,在测试类中如果想要打开某个窗口,直接new 登录窗口();即可
JFrame jFrame = new JFrame();// 创键了一个窗体
jFrame.setSize(width:?,width:?)// 设置窗体的大小
jFrame.setVisible(true);// 让窗体可视化(一般写在最后)
this(调用者、对象).setTitle("标题");//设置窗口标题
this.setAlwaysOnTop(true); // 界面置顶
this.setLocationRelativeTo(null); // 界面居中放置
this.setLayout(null); // 取消默认的居中放置,只有取消了才会按照xy轴的方式添加组件
组件不是直接放进JFrame中的,JFrame内有一个隐藏容器,可以用getContentPane()获取
1.ContentPane一直在JFrame内,不需要手动添加
2.ContentPane不包括标题和JMenuBar
3.用法:this.getContentPane().add(jLabel);
this.setDefaultCloseOperation(参数);//设置默认关闭方式
参数-0、1、2、3:
DO_NOTHING_ON_CLOSE = 0 // 不允许关掉
HIDE_ON_CLOSE = 1 // 默认关闭方式==不写整条语句
DISPOSE_ON_CLOSE = 2 // 当全部窗口都被关闭时,虚拟机终止运行,必须所有窗口都设置了此项才能生效
EXIT_ON_CLOSE = 3 // 当其中一个窗口被关闭时,虚拟机停止运行
JMenuBar最上层的菜单
1.先创建JMenuBar // JMenuBar jMenuBar = new JMenuBar();
2.再创建JMenu // JMenu jMenu1 = new JMenu("选项");
3.再创建JMenuItem // JMenuItem jMenuItem2 = new JMenuItem("重新登录");
4.再把JMenuItem放到JMenu里面 // jMenu1.add(jMenuItem1);
5.把JMenu放到JMenuBar里面 // jMenuBar.add(jMenu1);
6.最后再把JMenuBar添加到整个JFrame界面中 // this.setJMenuBar(jMenuBar);
JLabel管理文字和图片的容器
1.创建一个图片ImageIcon的对象
ImageIcon icon = new ImageIcon("图片相对路径");
2.创建一个JLabel的对象并把管理对象放进去(管理容器)
JLabel jLabel = new JLabel(icon);
3.给图片添加边框
// 0:表示让图片凸起来 BevelBorder.RAISED 
// 1:表示让图片凹下去
例:jLabel.setBorder(new BevelBorder(BevelBorder.LOWERED));// 凹下去
4.把管理容器添加到界面(JFrame)中(默认放在最中央)
this.add(jLabel);
4.1指定图片在管理容器中的位置(单位:像素)参数:x,y,图片长,图片宽
jLabel.setBounds(0,0,258,258);
3.2把jLabel添加进隐藏容器
this.getContentPane().add(jLabel);
事件
事件源:按钮 图片 窗体……
事件:某些操作如:鼠标单击,鼠标划入……
绑定监听:当事件源上发生了某个事件,则执行某段代码
KeyListener 键盘监听
MouseListener 鼠标监听 按住不松会持续触发
ActionListener 动作监听(只能监听空格和鼠标单击)
1.创建按钮
JButton jtb = new JButton("点我呀");
2.设置按钮的位置和大小
jtb.setBounds(0,0,100,50);
3.绑定动作监听(匿名内部类)
jb.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
    System.out.println("达咩~不要点我哟");
    }
});
3.1用类实现ActionListener的绑定动作监听写法
jb.addActionListener(this);// 在类内实现接口里的抽象方法
4.把按钮添加到界面中
this.getContentPane().add(jtb);
注意:Object source = e.getSource();语句可以用来获取是哪个按钮被触发了,在重写里可以与按钮对象进行比较
// 给整个界面添加键盘监听
        this.addKeyListener(this);
// 获取输入的键
        int keyCode = e.getKeyCode();
// 删除隐藏容器里的组件
        this.getContentPane().removeAll();
// 刷新界面
        this.getContentPane().repaint();
 // 创建一个弹窗
JDialog jDialog = new JDialog();
 // 弹窗不关闭就无法进行接下来的操作
jDialog.setModal(true);
匿名内部类:
1.什么是匿名内部类?
隐藏了名字的内部类,可以写在成员位置,也可以写在局部位置
2.匿名内部类的格式?
new 类名或接口名(){
    重写方法;
};
3.格式的细节
包含了继承或实现,方法重写,创建对象
4.使用场景
当方法的参数是接口或类时
以类为例,可以传递这个类的$子类对象,如果$子类只要使用一次,就可以用匿名内部类简化代码
适配器设计模式:
1、当一个类中的抽象方法过多,但我只要使用其中一部分的时候,就可以适配器设计模式
2、书写步骤:
编写中间类 接口名+Adapter,实现对应的接口
对接口中的抽象方法进行空实现
让真正的实现类继承中间类,并重写需要使用的方法
为了避免其他类创建适配器类对象,中间的适配器类用abstract进行修饰
注意:如果实现类要继承其他父类,只要让中间类继承父类。让实现类再继承中间类即可
接口的定义和使用:
接口代表规则,是行为的抽象。想要让哪个类拥有一个行为,就让这个类实现对应的接口就可以了
当一个方法的参数是接口时,可以传递接口所有实现类的对象,这种方式称之为接口多态
// 多态的弊端:无法调用子类特有的方法
接口用关键字interface来定义 public interface 接口名{};
接口不能实例化
接口和类之间是实现关系,通过implements关键字表示 public class 类名 implements 接口名{};
接口的子类(实现类)要么重写接口中的所有抽象方法 要么是抽象类
接口和接口之间是继承关系,可以单继承,也可以多继承
如果实现类实现了最下面的子接口,那么要重写所有的抽象方法
注意1:接口和类的实现关系,可以单实现,也可以多实现
public class 类名 implements 接口名1,接口名2{};
注意2:实现类还可以在继承一个类的同时实现多个接口
接口中成员的特点:
成员变量 只能是常量
默认修饰符 public static final
构造方法 没有
成员方法
JDK7以前只能是抽象方法
默认修饰符 public abstract
public class 类名 extends 父类 implements 接口名1,接口名2{};
JDK8以后接口中新增的方法
允许在接口中定义 默认 方法,需要使用关键字defualt修饰
作用:解决接口升级的问题
接口中默认方法的定义格式
public defualt 返回值类型 方法名(参数列表){方法体}
范例:public default void show(){}
接口中默认方法的注意事项:
默认方法不是抽象方法,所以不强制被重写。但是如果被重写,重写的时候要用到default关键字
public可以省略,default不能省略
如果实现了多个接口,多个接口中存在名字相同的默认方法,子类就必须对该方法进行重写
允许在接口中定义static方法,需要使用关键字static修饰
接口中静态方法的定义格式:
格式:public static 返回值类型 方法名(参数列表){}
范例:public static void(){}
接口中静态方法的注意事项:
静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
public可以省略,static不能省略
JDK9的新增方法
接口中 私有方法 的定义格式:
格式1:private 返回值类型 方法名(参数列表){}
范例1:private void show(){}
格式2:private static 返回值类型 方法名(参数列表){}
范例2:private static void show(){}

final修饰方法:表明该方法是最终方法不能被重写 public final void show(){}// 不能被继承
final修饰类:表明该类是最终类不能被即继承 public final class 类名(){}
final修饰变量:表明该变量是常量 final int A = 10;

静态(static)代码块{
    数据的初始化;
}// 就算类被多次调用,也不会重复执行
如果同时使用两个包中的同类名,需要用到全类名
多态中强制类型转换能解决什么问题?
可以转换成真正的子类类型,从而调用子类的特有功能
转换类型与真实对象类型不一致会报错
转换的时候用instanceof关键字进行判断
if(a instanceof Dog){
    Dog d = (Dog) a;
    d.lookHome;
}
if(a instanceof Dog d){// JDK14之后的特性:强转对象类型和判断可以写在一行
    d.lookHome;
}
在构造方法中super(参数);相当于调用父类带参构造方法,不写虚拟机也会默认生成
在构造方法中this(null,0,“代启航”);表示调用本类其他构造方法,一般用于创建默认值
// 以上两点必须写在构造方法内的第一行
方法重写:当父类方法不能满足子类现在的对象的需求时,我们就需要把这个方法进行重写。
// 注意:子类中重写的方法上面要加上@Override
例:
@Override
public void eat(){
    sout("吃意大利面");
}
继承
继承是面向对象的三大特征之一,可以让类跟类之间产生子父的关系
可以把多个子类中重复的代码抽取到父类中,子类可以直接使用,减少代码冗余,提高代码的复用性
public class 子类 extends 父类{}
子类可以得到父类的属性和行为,子类可以直接使用
子类可以在父类的基础上新增其他功能,子类更强大
静态方法中没有this关键字
静态方法中只能访问静态
非静态方法可以访问所有
static表示静态,是Java中的一个修饰符,可以修饰成员方法,成员变量
被static修饰的成员变量,叫做静态变量
特点:被该类所有对象共享 不属于对象,属于类 随着类的加载而加载,优先于对象存在
调用方式:类名调用(推荐)、对象名调用
被static修饰的成员方法,叫做静态方法
特点:多用在测试类和工具类中 Javabean类中很少会用
调用方式:类名调用(推荐)、对象名调用
工具类:帮助我们做一些事情的,但不描述任何事物的类
1.类名见名意、2.私有化构造方法、3.方法定义为静态
==============================
System.exit(0); // 停止虚拟机运行
loop: while(true){// loop是循环的标号方便跳出
    switch(){
        case "1" -> break loop; // 跳出指定循环
    }
};
包装类(引用数据类型?):
char Character
int Integer // 其他类型不变
集合ArrayList<E>:
集合是泛型,只能存储引用数据类型,自动变化长度
例:ArrayList<String> list = new ArrayLIst<>();    // 创建一个字符串类型的集合
ArrayList成员方法:
增:boolean add(E e) 添加元素,返回值表示是否添加成功// 可以忽略返回值,一定是true
删:boolean remove(E e) 删除指定元素,返回值表示是否删除成功
      E remove(int index) 删除指定索引的元素,返回被删除的元素
改:E set(int index,E e)修改指定索引下的元素,返回原来的元素
查:E get(int index)    获取指定索引的元素
      int size()    返回集合的长度
释放空间 trimToSize();
=================
// StringJoiner的构造方法
StringJoiner(间隔符号)    创建一个StringJoiner对象,指定拼接时的间隔符号
StringJoiner(间隔符号,开始符号,结束符号)创建一个StringJoiner对象,指定拼接时的间隔符号、开始符号、结束符号
// StringJoiner的成员方法
public StringJoiner add(添加的内容)    添加数据,并返回对象本身
public int length()                    返回长度(字符出现的个数)
public String toString();                把StringBuilder转换为String
// StringBuilder构造方法:
public StringBuilder()        创建一个空白可变字符串对象,不含有任何内容
public StringBuilder(String str)    根据字符串内容,来创建可变字符串对象    
// StringBuilder常用方法:
public StringBuilder append (任意类型)    添加数据,并返回对象本身
public StringBuilder reverse()            反转容器中的内容
public int length()                    返回长度(字符出现的个数)
public String toString();                把StringBuilder转换为String
==============================================
String tochararray(); // 把字符串转换成字符数组,通过索引可以简单改变字符串
String new String(arr); // 把字符数组转换成字符串
String replace(旧值,新值)    替换    // 只有返回值才是替换之后的结果,replace区分大小写
// 替换相当于创建了一个新的字符串,返回值已经是替换完成之后的结果,无需手动拼接
String substring(int beginindex, int endindex)    截取
String substring(int beginindex)    截取到末尾    // 包头不包尾,包左不包右
String charAt(index) 选取
boolean startswith(String string);// 如果字符串以string开头,返回true,否则返回false
boolean equals(要比较的字符串)
boolean equalsIgnoreCase(要比较的字符串) // 忽略大小写 
   // 构造方法快捷键ALT +fn + INSERT || 鼠标右键生成
    // 构造方法快捷键CTRL + SHIFT + , 需要ptg插件
标准的JavaBean类
1.类名需要见名知意
2.成员变量使用private修饰
private String name;
private int age;
3.提供至少两个构造方法
    1-无参构造方法(如果构造了带参方法,无参方法要手动写)
    public Object(){}
    2-带全部参数的构造方法
    public Objeic(String name,int age){
    if(age<18) System.out.println("数据非法");// 等
}
4.成员方法
    1.提供每一个成员变量对应的setXxx()/getXxx()
    public void setXxx(){
        this Xxx = Xxx;
}
    public 返回值类型 getXxx(){
        return Xxx;
}
    2-如果还有其他行为,也需要写上
this关键字:区分局部变量和成员变量
权限修饰符:private(私有的):可以修饰成员变量和成员方法
被private修饰的成员只能在本类中才能访问
例:demo8
类:(设计图)是共同特征的描述
对象:真实存在的具体实例
类名 对象名 = new 类名();
public void 类名{
    1.成员变量(代表属性的,一般指名词)
    2.成员方法(代表动作的,一般指动词)
}
二维数组:
静态:int[][] arr = {{a,b,c},{d,e,f}};
动态:int[][] arr = new int[m][n];
基本数据类型:数据是存储在自己的空间中
特点:赋值给其他的变量,也是赋的真实的值
引用数据类型:数据是存储在其他空间中,自己空间中存储的是地址值
特点:赋值给其他变量,赋的是地址值
形参:全称形式参数,是指方法定义中的参数    例:public static void 方法名(int num){}; ->num
实参:全称实际参数,方法调用中的参数    例:方法名(num); ->num    也可能是实际的值
方法的重载:同一个类(class)中,方法名相同,参数不同的方法,与返回值无关。
参数不同:个数不同、类型不同、顺序不同        // 虚拟机是通过参数来判断在方法重载中真正调用的方法

方法运行时使用的内存,比如main方法运行,进入方法栈中执行

new来创建的,一定都存储在堆内存
48-'0'
65-'A'
97-'a'
'小写字母'&'-'=='大写字母'    // 括号里是下划线
java
//byte short char 三种类型的数据在运算的时候,都会直接提升成为int,然后再进行运算!!!
import java.util.Scanner;//1,导包
Scanner sc = new Scanner(System.in); //2,创建对象
int i = sc.nextInt(); //3,接受数据
随机数:
import java.util.Random;
Random r = new Random();
int num = r.nextInt(100);    // 0~99
int num = r.nextInt(100)+1;    // 1~100;包头不包尾,包左不包右
数组动态初始化:
格式:数据类型[] 数组名 = new 数据类型[数组长度];
范例:int[] arr = new int[3];
//在使用+=,-=,*=,/=,%=,的时候,运算结果会强制转换成为与要赋值的变量一致
例:short i;i += 1等同于i = (short)(i + 1)
&与,|或,^异或,!非(单独使用);
&&短路与,||短路或;//效率比较高
三元运算符:关系表达式 ?表达式1 :表达式2;    //当结果是true时,结果为表达式1,否则是表达式2
命令提示符(cmd)
启动:        win+R,输入cmd回车
切换盘符        盘符名称:
进入文件夹        cd 文件夹名称
进入多级文件夹    cd 文件夹1\文件夹2\文件夹3
返回上一级        cd ..
直接回根路径    cd \
查看当前内容    dir
清屏            cls
退出            exit
//运算次数越少,代码越高级

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值