Java记录

这篇博客详细记录了Java编程的各种知识点,包括线程创建、比较器、枚举类和注解的使用,集合接口的实现与操作,IO流,网络编程,反射机制,Lambda表达式以及Stream API的应用。还涉及到了数据类型转换、异常处理、内部类、线程安全问题的解决等重要内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JAVA记录

  1. Java中一个实数默认为double类型,在末尾加f(F)可变为float

    获取闭区间[a,b]中的随机数:

    (int) (Math.random() * (b - a + 1)) + a //不是闭区间的转换成闭区间

  2. int a = 123444532322324424242l,赋给a的数字太大可以在其后加l

  3. 包名:多单词组成时所有字母均小写zzzxxxccc

    类名,接口名:多单词组成时XxxYyyZzz

    变量名,方法名:多单词组成时xxxYyyZzz

    常量名:所有字母均大写,多个单词时XXX_YYY_ZZZ

  4. 方法的重载:同名的函数通过不同的形参做类似的事情

    要求:1. 函数的形参个数

    2.函数的形参顺序

    3.函数的形参数据类型

    注意:若两函数同名同参但返回值类型不同,构不成函数的重载

    //可变个数形参的方法
    public void f(String ... vals)
    {
        
    }
    
  5. 构造器:


class A
{
    public int i;
    public A (int j)
    {
        i = j;
    }   // 构造函数,就是在创建对象时就对类的属性赋初值`

    public void show(){
        System.out.printf ("%d\n",i);
  }
}

class Startup
{
    public static void main (String[] args)
    {
        A aa = new A(3);
        aa.show();
    }
}
class Customer
{
    public Customer()
    {
        System.out.printf("100");
    }
    
    public Customer(int age)
    {
        this();     //通过this(参数列表)的形式来修饰构造器
                    //必须写在当前构造器的首行
        this.age=age;
    }
    
    public Customer(String name, int age)
    {
        this(age);
        this.name=name;
    }
}

默认构造器的权限与类的权限保持一致


6.关键字static

若在类的属性前面加上关键字static,则用该类创建出的若干个对象共用同一个属性,同时在创建的对象中可以用类名.属性名的方式访问类中的东西,但必须保证所访问的东西是非私有(private)的

静态方法不能访问非静态成员;非静态方法可以访问静态成员。

修饰符类内部同一个包不同包的子类同一个工程
privateYes
(缺省)YesYes
protectedYesYesYes
publicYesYesYesYes

对于class的权限修饰只可以用public和default(缺省)

  • public类可以在任意地方被访问
  • default类只可以被同一个包内部的类访问

7.继承

一个新类从已有的类那里获得其已有的属性和方法,叫做类的继承,新类叫做子类也叫派生类,已有的类叫做父类也叫基类.

实现代码:

class B extends A
{

}

注意:私有的不能被继承,父类中的构造方法也不能被子类继承,所以要想在子类中对继承父类的属性进行初始化,要用到super,方法是super ( i , j ),深层意思是以这种形式调用了父类中的构造方法

8.方法重写

​ 指在子类中重新定义父类中已有的方法.

​ 子类中不允许出现与父类中同名同参不同返回值的方法.

class A
{
    protected void f()
    {
        System.out.printf("Hello");
    }
}

class B extends A
{
	public void f()
    {
        System.out.printf("World");
    }
    //此为方法的重写,需注意重写方法的访问权限不小于原方法的访问权限
}

虽说是方法的重写,但是B类中存在两个f函数,A中继承过来的f函数隐藏存在

不能重写父类中私有化的方法

若被重写方法的返回值类型是A类型,则重写方法的返回值类型可以是A类或者A的子类。比如(Object 》String)

  1. 多态

    使用前提:1. 要有类的继承关系 . 2. 子类一般要重写父类中的方法,否则没有必要用多态 .

    3.多态只适用于方法,不适用于属性

class A
{
    public void f ()
    {
        System.out.printf("AAAA");
    }
}

class B extends A
{
    public void f()
    {
        System.out.printf("BBBB");
    }
    public void g()
    {
        System.out.printf("GGGG");
    }
}

class Startup 
{
    public static void main (String[] args)
    {
        /*
        	A aa = new B();
        	aa.f();
        */
        A aa = new A();
        B bb = new B();
        aa.f();          //结果是AAAA
        bb.f();          //结果是BBBB

        //aa是父类,比作动物,bb是子类,比作狗

        aa = bb;         //相当于把狗当动物看,可以
        //bb = aa;         相当于把动物当狗看,不可以
        aa.f();          //结果是BBBB

        /*子类可以发送给父类,(aa=bb)
        父类不可以发送给子类,(bb=aa)*/

    }
}

这就是多态,同一句代码实现不同的功能。

注意aa.g()是错的,父类的引用指向子类后,不能调用子类中特有的成员,只可以访问重写的方法或者从父类继承过来的成员

  1. 抽象类(植物类,动物类······)
abstract class A
{
    public abstract void f();
}

​ 没有方法体的方法叫做抽象方法

​ 包含抽象方法的类必须声明为抽象类

​ 抽象类不一定有抽象方法

​ 不能new出抽象类对象,但可以定义一个抽象类的引用

abstract 不能用来修饰私有的方法、static的方法、final的方法、final的类

  1. final 关键字

    可修饰整个类和类中的成员

    // 修饰整个类时表示该类是最后一个类,不可被继承
    class final A           //或者是 final class A
    {
    	
    }
    
    // 修饰成员变量时表示该变量是一个常变量且必须赋给它一个初值,并且不能改变
    class B
    {
        final public int x = 3;
        //或者通过构造方法来给它赋初值
        /*			final public int y;
                    public B
                    {
                        y = 3;
                    }
        */
    }
    
    // 修饰成员方法时表示该方法不能被重写
    class C
    {
        final public void f()
        {
            
        }
    }
    
    1. 接口

      JAVA中接口和类是同级关系,jdk7以前接口中可以定义:全局常量和抽象方法

      jdk8以后,也可以定义静态方法和默认方法

        interface it1
        {
             int x = 1;      //必须赋初值
             void f();
      }
            /*接口中的属性是public static final 类型,抽象方法是public abstract 类型
              可以写成上述格式是因为可以被省略,因为其只能是public static final 和 public               abstract类型*/
      
      interface it2
      {
          int y = 1;
          void g();
      }
      
      abstract class A implements it2
      {
      	public void h()
      	{
      	
      	}
      }
      //可以通过implements来获得it2中的成员
      
      interface it1
      {
      }
      interface it2
      {
      }
      interface it3 extends it1,it2
      {
      }
      //接口可以继承接口,可以继承多个
      
      interface it1
      {
      }
      interface it2
      {
      }
      class A
      {
      }
      class B extends A implements it1,it2
      {
      }
      //子类在继承父类的同时也可以通过implements来实现一个或多个接口
      
      interface it1
      {
          void f();
      }
      
      class A implements it1
      {
      	public voif f()
      	{
      		System.out.printf ("123");
      	}
      	public void g()
      	{
      	}
      }
      
      class StartUp
      {
          public static void main (String[] args)
          {
              it1 it;
              it = new A();
              it.f();
              it.g();  //error,只能调用从接口包含过来的方法
              /*接口不可以new接口对象,可以定义一个接口引用类型的变量,将其指向实现接口的对象,
                达到多态的目的*/
          }
      }
      

      13.数组

      //第一种方式,赋值了
      int number[];
      number = new int[]{1,2,3,4,5};
      
      //第二种方式,没有赋值
      int sum1[] = new int[4];
      
      //第三种方式
      int arrays[] = new int[]{2,3,1,4,5,2,1}
      

      14.

      package com.Tencent                //放在代码的第一行
         
      /*导包操作:1. import com.Tencent.*          导入该包的全部东西
                2. import com.Tencent.A          只导入某一个类,该类应为public,成员也应为
                                                 Public
      
      

      15.Javabean

      所谓Javabean是指符合如下标准的Java类

      • 类是公有的
      • 有一个无参的构造器
      • 有属性,且有对应的get,set方法

      16.instanceof

      a instanceof A
      //判断对象a是否是类A的实例
      //是    返回true
      
      1. equals

        equals是一个定义在Object类中的方法,作用是比较两个对象的地址是否相同,但是一些类中重写了这个方法,作用变为比较两个对象的内容是否相同。

        public boolean equals (Object obj){
            return (this == obj);
        }
        
        //重写equals方法思路:
        public boolean equals (Object obj){
            if (this == obj){
                return true;
            }
            
            if (obj instanceof User){
                User us = (User)obj;
                return this.age == u.age && this.name.equals(us.name);
            }
            return false;
        }
        
      2. 包装类

        基本数据类型包装类
        intInteger
        doubleDouble
        floatFloat
        byteByte
        charCharacter
        shortShort
        longLong
        booleanBoolean
  • 基本数据类型转化为包装类

    Integer int1 = new Integer(1);
    //实际就是调用包装类得构造器
    
  • 包装类转化为基本数据类型

    Double double1 = new Double(1.1);
    double number1 = double1.doubleValue();
    
  • 自动装箱、自动拆箱

    //自动装箱
    Integer i1 = 10;
    
    //自动拆箱
    int num = i1;
    
  • 基本数据类型、包装类转换为String类型

    //基本数据类型-->String
    //方式一:
    int a = 12;
    String str1 = String.valueOf(a);
    //方式二:
    String str2 = 12 + "";
    
    //包装类转化为String
    Float b = 11.1;
    String str2 = String.valueOf(b);
    
  • String转化为基本数据类型

    //String-->基本数据类型
    String s1 = "123";
    int num = Integer.parseInt(s1);
    
    1. 单例设计模式
    //饿汉式
    
    class A{
        private A(){}
        private static A aa = new A();
        public static A getA(){
            return aa;
        }
    }
    
    //懒汉式
    //目前还存在多线程安全问题,以后可修复
    
    Tips:加一个synchronized 就可以修复线程安全问题
    class B{
       private B(){}
       private static B bb = null;
       public static B getB(){
       	if(bb == null){
       		synchronized(B.class){
       			  if (bb == null){
               		bb = new B();
           		}
       		}
       	}
           return bb;
       }
    }
    
    1. 代码块
    // 静态代码块
    static {
        
    }
    //作用:对类的信息进行初始化
    

    static 代码块随着类的加载而执行,且只执行一次

    //非静态代码块
    {
       
    }
    //作用:在创建对象时,对对象中的属性进行初始化 
    

    非static 代码块随着对象的加载而执行

    21.内部类

    分为成员内部类(静态、非静态)vs 局部内部类(方法内,代码块内,构造器内)

    22.异常

    • try-catch-finally

      实际在开发过程中,一般不会去对运行时的错误进行try-catch

      //格式
      try{
          //可能出现异常的代码
      }catch(生成的对应的异常对象 对象名){
          e.printStackTrace()	//可以打印出对应的异常类型是什么
      }finally{
          //这里的代码一定会被执行,即使try中有return语句,catch中又出现异常或者catch中有return语句		等等
      }
      

      如果try块或catch块中有return语句,finally块里的语句会执行在try块或catch块中的return语句前。

      如果finally块里有return语句,则直接返回,而不执行try块或catch块里的return语句

    • throws+异常类型

      只是把异常往上反馈,谁调用我,谁解决我的异常,并没有真正的解决掉异常。

    • 手动抛出异常

      通过关键字throw来生成一个异常对象。注意:throws是一种异常的处理方式。

23.线程的创建
//方式一:继承于Thread类
1.创建一个类继承于Thread
2.重写run()-->  重写的内容就是此线程要做的事情
3.创建Thread类的子类对象
4.通过此对象调用start()

class SubThread extends Thread{
	public void run(){
	}
}

class SubThreadTest {
	SubThread t = new SubThread();
	t.start();
}

currentThread()是一个静态方法,通过Thread.currentThread()来调用,返回当前执行的线程

yield() 释放当前cpu的执行权

在线程A中调用线程B的join(),线程A就会进入阻塞状态,直到线程B执行完,A才会结束阻塞状态。注意这个方法会抛异常

sleep(long millitime) 让当前线程“睡眠”指定的毫秒数,在指定的时间内,当前线程阻塞.此方法会抛异常。

isAlive() 判断当前线程是否存活

24.线程的优先级

MAX_PRIORITY:10
MIN_PRIORITY:1
NORM_PRIORITY:5   -->  默认优先级

获取和设置优先级
getPriority();
setPriority(int i);

说明:高优先级的线程要抢占低优先级的资源,但是并不代表要等到高优先级的线程全部执行完以后才会执行低优先级的线程

25.线程的第二种创建方式(实现Runnable接口)

class MThread implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++){
            if (i % 2 == 0){
                System.out.println(i);
            }
        }
    }
}

public class Test {
    public static void main(String[] args) {
        MThread mThread = new MThread();
        Thread t1 = new Thread(mThread);
        t1.start();
    }
}

26.线程的生命周期

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rkryPavD-1666177889141)(…/…/AppData/Roaming/Typora/typora-user-images/1651656788753.png)]

27.解决线程安全问题

  • 方式一:同步代码块

    synchronized(同步监视器){
        //需要被同步的代码
    }
    
    说明:1.操作共享数据的代码,即为需要被同步的代码
    	 2.共享数据:多个线程共同操作的变量
    	 3.同步监视器,俗称锁。任何一个对象都可以充当监视器。
    	   要求:多个线程要共用同一把锁
    
  • 方式二:同步方法

    如果操作共享数据的代码完整的声明在一个方法中,可以将本方法声明为同步的
    
    class MThread implements Runnable {
        private int tickets = 50;
        @Override
        public void run() {
            while (true) {
                show();
            }
        }
    //将方法声明为同步的
        private synchronized void show(){//这里的监视器是this
            if (tickets > 0){
                System.out.println(Thread.currentThread().getName() + ": 票号为:" + tickets);
                tickets--;
            }
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            MThread mThread = new MThread();
    
            Thread t1 = new Thread(mThread);
            Thread t2 = new Thread(mThread);
            Thread t3 = new Thread(mThread);
    
            t1.start();
            t2.start();
            t3.start();
        }
    }
    
    说明:1.同步方法仍然涉及到同步监视器,只是不需要我们去显式的声明
    	 2.非静态的同步方法,同步监视器是this
    	 3.静态的同步方法,同步监视器是当前类本身
    
  • Lock锁方式解决

    class MThread implements Runnable {
        private int tickets = 50;
        private ReentrantLock lock = new ReentrantLock();
        @Override
        public void run() {
            while (true) {
                try {
                    lock.lock();//上锁
                    if (tickets > 0){
                        System.out.println(Thread.currentThread().getName() + ": 票号为:" + tickets);
                        tickets--;
                    }else{
                        break;
                    }
                }finally{
                    lock.unlock();//下锁
                }
            }
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            MThread mThread = new MThread();
    
            Thread t1 = new Thread(mThread);
            Thread t2 = new Thread(mThread);
            Thread t3 = new Thread(mThread);
    
            t1.start();
            t2.start();
            t3.start();
        }
    }
    

28.线程的通信

涉及到三个方法:1.wait()-->执行此方法,当前线程进入阻塞状态,并释放同步监视器
             2.notify()-->执行此方法,唤醒被wait()的一个线程,若有多个线程,则唤醒优先级高的
             3.notifyAll()-->执行此方法,唤醒所有被wait()的线程
             
            
说明:1.这三个方法必须使用在同步代码块或同步方法中
     2.三个方法的调用者必须是同步代码块或同步方法中的同步监视器,否则会出现异常
     3.这三个方法是定义在Object类中的方法
     
     
面试题:sleep()wait() 的异同:
1.相同点: 1)一旦执行,都会使当前线程进入阻塞状态
         2)都会抛异常
2.不同点: 1sleep()声明在Thread类当中,而wait()声明在Object类中
         2sleep()可以在任何需要的场景下调用,而wait()只能在同步方法或同步代码块中调用
         3sleep()不释放同步监视器,而wait()释放

29.线程的第三种创建方式(实现Callable接口)

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

//1.创建实现Callable接口的类
class c1 implements Callable{

//2.重写call()方法,注意,此方法有返回值,更强大
    @Override
    public Object call() throws Exception {
        int num = 0;
        for (int i = 0; i < 100; i++){
            num += i;
        }
        return num;
    }
}


public class CallTest {
    public static void main(String[] args) {
        
//3.创建实现Callable接口类的对象
        c1 c = new c1();
//4.将此Callable接口类的对象作为参数传递到FutureTask构造器中,创建FutureTask的对象
        FutureTask f1 = new FutureTask(c);
//5.将FutureTask的对象作为参数传递到Thread的构造器中,创建Thread对象,并调用start()方法
        new Thread(f1).start();
//6.获取Callable中call方法的返回值,调用get()方法,并处理异常
        try {
            Object sum = f1.get();
            System.out.println(sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

30.线程的第四种创建方式(线程池)

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

class thread1 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 50; i++){
            if(i % 2 == 0){
                System.out.println(i);
            }
        }
    }
}

public class ThreadPool {
    public static void main(String[] args) {
        //1.提供指定线程数量的线程池
        ExecutorService service = Executors.newFixedThreadPool(10);
        
        //设置线程的属性
        ThreadPoolExecutor serv = (ThreadPoolExecutor) service;//获取线程池的对象
        serv.setCorePoolSize(12);

        //2.执行指定线程的操作,需提供实现Runnable接口或Callable接口实现类的对象
        service.execute(new thread1());  //适合用于Runnable

        //service.submit(Callable callable)  //适合用于Callable

        //3.关闭连接池
        service.shutdown();
    }

}


31.String

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jy8FIto0-1666177889142)(…/…/AppData/Roaming/Typora/typora-user-images/1652011605867.png)]

String —> char[] :

//调用String的toCharArray方法
public void test1() {
        String str1 = "hello";
        char[] arry = str1.toCharArray();
    }

char[] —> String :

//调用String的构造器
char[] arry2 = new char[]{'h','e','l','l','o'};
        String str2 = new String(arry2);
        System.out.println(str2);

String —> byte[] :

//调用String的getBytes方法
String str3 = "abc123";
        byte[] bytes = str3.getBytes();
        System.out.println(Arrays.toString(bytes));

32.字符串的三种形式比较

  • String 不可变的字符串;底层用char[] 存储
  • StringBuffer 可变的字符串;线程安全的,效率低;底层用char[] 存储
  • StringBuilder 可变的字符串;线程不安全的,效率高;底层用char[] 存储
  • 开发指导: 建议使用StringBuffer(int capacity)

33.JDK8 之前日期和时间的API

1.System类中的currentTimeMillis()--> 返回当前时间与197011000秒之间的以毫秒为单位的时间差

2.java.util.Date类
构造器:
Date date1 = new Date()   //创建对应当前时间的Date对象
Date date2 = new Date(时间戳)   //创建指定毫秒数的Date对象
方法:
date1.toString()   //显示当前的年、月、日、时、分、秒
date1.getTime()   //获取当前Date对象的毫秒数(时间戳)

3.java.sql.Date
构造器:
java.sql.Date date3 = new java.sql.Date(时间戳)
方法:
date3.toString()   //显示年、月、日
date3.getTime()    //获取当前Date对象的毫秒数(时间戳)

4.java.util.Date -->  java.sql.Date
Date date4 = new Date()
java.sql.Date date5 = new java.sql.Date(date4.getTime())

SimpleDateFormat 的使用
public class SimpleDateFormatTest {

    @Test
    public void testSimpleDateFormat() throws ParseException {
        //使用默认的构造器
        SimpleDateFormat sdf = new SimpleDateFormat();
        Date date1 = new Date();
        //格式化:日期 ---> 字符串
        String format = sdf.format(date1);
        System.out.println(format);  //   2022/5/11 上午11:22
        //解析:  字符串 ---> 日期
        Date date2 = sdf.parse(format);  //会抛异常
        System.out.println(date2);  //Wed May 11 11:22:00 CST 2022

        //使用指定形式的构造器
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String format1 = sdf1.format(date1);
        System.out.println(format1);  //2022-05-11 11:38:11

    }

}

Calendar 日历类(抽象类)的使用

1.实例化
//方式一:创建其子类(GregorianCalendar)的对象
new GregorianCalendar();
//反式二:调用静态方法getInstance()
Calendar calendar = Calendar.getInstance();

2.常用方法:
//get()
int days = calendar.get(Calendar.DAY_OF_MONTH);

//set()
calendar.set(Calendar.DAY_OF_MONTH,12);//将calendar本身改了

//add()
calendar.add(Calendar.DAY_OF_MONTH,3);//在原有的基础上加了3天

//getTime()  日历类 ---> Date
Date date = calendar.getTime();

//setTime    

34.JDK8 以后的日期和时间的API

1.LocalDate   LocalTime   LocalDateTime

//now()   获取当前的日期、时间、日期+时间
LocalDate date = LocalDate.now();
LocalTime time = LocalTime.now();
LocalDateTime now = LocalDateTime.now();

//of()    设置指定的年、月、日、时、分、秒
LocalDateTime of = LocalDateTime.of(2022, 5, 11, 16, 30, 0);

//get()   获取一些信息
System.out.println(now.getDayOfMonth());
System.out.println(now.getMonthValue());
System.out.println(now.getMinute());

//with    修改一些信息(不可变性)
System.out.println(now.withHour(5));  //修改小时,原来的还不变

//plus(增加)  minus(减少)
LocalDateTime localDateTime1 = now.plusDays(2);
LocalDateTime localDateTime2 = now.minusHours(10);

2.Instant类的使用

public void test2(){
        //now()  获取本初子午线对应的时间
        Instant instanced = Instant.now();
        System.out.println(instanced);

        //添加时间的偏移量
        OffsetDateTime offsetDateTime = instanced.atOffset(ZoneOffset.ofHours(8));
        System.out.println(offsetDateTime);

        //toEpochMilli()  获取自1970年1月1日0时0分0秒开始的毫秒数
        long l = instanced.toEpochMilli();
        System.out.println(l);

    }

3.DateTimeFormatter的使用(格式化或解析时间、日期)

public void test3(){
        //自定义格式
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh-mm-ss");
        
        //格式化
        String time1 = dateTimeFormatter.format(LocalDateTime.now());
        System.out.println(time1);//2022-05-11 07-36-56

        //解析
        TemporalAccessor accessor = dateTimeFormatter.parse("2022-05-11 07-36-56");
        System.out.println(accessor);
        //{MicroOfSecond=0, HourOfAmPm=7, NanoOfSecond=0, MinuteOfHour=36, 				            SecondOfMinute=56, MilliOfSecond=0},ISO resolved to 2022-05-11
    }

35.JAVA比较器

35-1. 实现comparable接口(自然排序)
import org.junit.Test;

import java.util.Arrays;

class Things implements Comparable{
    private double price;
    private String name;

    public Things() {
    }

    public Things(double price, String name) {
        this.price = price;
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Things{" +
                "price=" + price +
                ", name='" + name + '\'' +
                '}';
    }

    @Override
    public int compareTo(Object o) {
        if (o instanceof Things){
            Things t = (Things) o;
            if (this.price > t.price){
                return 1;
            }else if(this.price < t.price){
                return -1;
            }else{
                return 0;
            }
        }
        throw new RuntimeException("类型不一致");
    }
}

public class ComparTest {
    public static void main(String[] args) {
        Things things[] = new Things[4];
        things[0] = new Things(100,"HUAWEI");
        things[1] = new Things(90,"HONOR");
        things[2] = new Things(80,"MI");
        things[3] = new Things(50,"OPPO");

        Arrays.sort(things);
        System.out.println(Arrays.toString(things));

    }

}

35-2.Comparator接口的使用 (定制排序)
//重写compare(Object o1, Object o2)方法,比较o1 和 o2的大小

public class ComparTest {
    public static void main(String[] args) {
        Things things[] = new Things[4];
        things[0] = new Things(100,"HUAWEI");
        things[1] = new Things(90,"HONOR");
        things[2] = new Things(80,"MI");
        things[3] = new Things(50,"OPPO");

        Arrays.sort(things,new Comparator(){

            @Override
            public int compare(Object o1, Object o2) {
                if (o1 instanceof Things && o2 instanceof Things){
                    Things t1 = (Things)o1;
                    Things t2 = (Things)o2;
                    if (t1.getName().equals(t2.getName())){
                        return -Double.compare(t1.getPrice(),t2.getPrice());
                    }else{
                        return t1.getName().compareTo(t2.getName());
                    }
                }
                throw new RuntimeException("类型不一致");
            }
        });
        System.out.println(Arrays.toString(things));

    }

}

36.枚举类和注解

36-1.自定义枚举类
  • 类的对象只有有限个,确定的,称此类为枚举类

  • 当需要定义一组常量时,建议用枚举类

  •   //自定义枚举类
      class Via {
          //1.声明Via类的属性,private final修饰
          private final String name;
          private final String deso;
      
          //2.私有化类的构造器,并给属性赋初值
          private Via(String name, String deso) {
              this.name = name;
              this.deso = deso;
          }
      
          @Override
          public String toString() {
              return "Via{" +
                      "name='" + name + '\'' +
                      ", deso='" + deso + '\'' +
                      '}';
          }
      
          //3.提供当前枚举类的多个对象,public static final修饰
          public static final Via v1 = new Via("Spring","春暖花开");
          public static final Via v2 = new Via("Summer","夏日炎炎");
          public static final Via v3 = new Via("Autumn","落叶飘零");
          public static final Via v4 = new Via("Winter","冬泳怪鸽");
      }
    
  •   enum Via {
          //1.使用enum关键字来定义,可省略 public static final 及其他相同的部分
           v1("Spring","春暖花开"),
           v2("Summer","夏日炎炎"),
           v3("Autumn","落叶飘零"),
           v4("Winter","冬泳怪鸽");
      
          //2.声明Via类的属性,private final修饰
          private final String name;
          private final String deso;
      
          //3.私有化类的构造器,并给属性赋初值
          private Via(String name, String deso) {
              this.name = name;
              this.deso = deso;
          }
      
          @Override
          //一般不重写,有需求可以重写
          public String toString() {
              return "Via{" +
                      "name='" + name + '\'' +
                      ", deso='" + deso + '\'' +
                      '}';
          }
      }
    

    使用enum定义的枚举类继承于Enum类,常用方法如下:

    1.values() — 返回枚举类型的对象数组,可以方便遍历内容

    2.valuesOf(String objName) — 返回枚举类中对象名是objName的对象

36-2.注解

jdk中的四种元注解:

  • Retention — 指定所修饰的Annotation的生命周期:SOURCE/CLASS(默认)/RUNTIME
  • Target — 用于指定被修饰的Annotation能用来修饰那些程序元素
  • Documented — 表示所修饰的注解在被javadoc解析时,会保留下来
  • Inherited — 被它修饰的Annotation具有继承性

37.集合

  • Collection接口 :单列集合,用来存储一个一个的对象
    • List 接口 — 存储有序的、可重复的数据
    • Set 接口 — 存储无序的、不可重复的数据
  • Map接口 :双列集合,用来存储一对(key - value)一对的数据
37-1.Collection接口中定义的方法
  1. add()

  2. addAll(Object e) — 将另一个集合中的数据存到当前调用者的集合中

  3. clear()

  4. size()

  5. isEmpty()

  6. contains(Object obj) — 判断当前集合中是否包含obj,要求要重写obj中的equals()方法

  7. containsAll(Collection coll) — 判断coll集合中的元素是否都存在于当前集合中

  8. remove(Object obj) — 删除当前集合中的obj元素

  9. removeAll(Collection coll) — 删除当前集合中包含的coll集合中的元素

  10. retainAll(Collection coll) — 获取当前集合和形参集合的交集,实际就是对当前集合进行了修改

  11. equals(Collection coll) — 判断当前集合和形参集合中的元素是否都相同

  12. toArray() — 集合–> 数组

  13. Arrays.asList() — 数组–> 集合

  14. iterator — 遍历集合中的元素

  Iterator iterator = coll.iterator();
          while(iterator.hasNext()){
              System.out.println(iterator.next());
          }

15.for遍历集合或数组中的元素

for (Object obj : coll){
    System.out.println(obj);
}
37-2.List接口

主要实现类:

ArrayList:List接口的主要实现类,线程不安全,效率高,底层使用Object[] elementDate 数组存储

LinkedList:对于频繁的插入、删除等操作,比ArrayList效率高,底层使用双向链表存储

Vector:古老实现类,线程安全的,效率低,底层使用Object[] elementDate 数组存储

List接口常用方法

  1. get( int index) — 获取指定位置的元素
  2. indexOf(Object obj) — 返回obj在集合中首次出现的位置(若没有,返回-1)
  3. lastIndexOf(Object obj) — 返回obj在集合中末次出现的位置(若没有,返回-1)
  4. Object remove (int index) — 移除指定位置的元素并返回
  5. Object set ( int index, Object ele) — 设置指定位置的元素为ele
  6. List subList (int fromIndex, int toIndex) — 返回从fromIndex到toIndex的左闭右开的子集合
37-3.Set接口

主要实现类:

HashSet:Set接口的主要实现类,线程不安全,可存储null

LinkedHashSet:HashSet的子类,遍历其内部数据时,可以按照添加的顺序遍历

TreeSet:可以按照添加对象的指定属性进行排序

向set接口中添加数据时,其所在的类一定要重写equals()和hashCode()方法,并且不能添加不同类型的数据

37-4.Map接口

主要实现类:

HashMap:Map接口的主要实现类,线程不安全,可存储null的key-value

LinkedHashMap:HashMap的子类,遍历其内部数据时,可以按照添加的顺序遍历,对于频繁的遍历操作,效率高于HashMap

TreeMap:保证按照添加的key-value对进行排序,实现排序遍历。考虑key的自然排序或定制排序。

Hashtable:古老的实现类,线程安全,不能存储null的key-value

Properties:Hashtable的子类,常用来处理配置文件,key-value都是String类型

key所在的类要重写equals()和hashCode()

values所在的类要重写equals()


HashMap的底层实现原理:jdk7

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KAoinRrM-1666177889143)(…/…/AppData/Roaming/Typora/typora-user-images/1653474221536.png)]

jdk8与7的不同:

  1. new HashMap(),底层没有创建一个长度为16的数组
  2. jdk8中数组改为Node,而非Entry[]
  3. 首次调用put()方法时,底层创建长度为16的数组
  4. jdk7底层结构:数组+链表。jdk8中底层结构:数组+链表+红黑树。当数组中某个索引位置上的元素以链表形式存在的数据个数>8,并且数组长度>64,此时此位置上的所有数据改为用红黑树存储

Map接口方法

  1. Set keySet() — 返回所有的key构成的Set集合
  2. Collection values() — 返回所有的value构成的Collection集合
  3. Set entrySet() — 返回所有key-value对组成的Set集合
37-5.Collections工具类
  1. reverse(List)
  2. shuffle(List) — 随机排序
  3. sort(List)
  4. sort(List,Comparator)
  5. swap(List,int i,int j) — 交换i,j处的元素
  6. Object max(Collection)
  7. Object max(Collection,Comparator)
  8. int frequency(Collection,Object) ---- 返回指定元素出现的频率
  9. void copy(List dest, List src) — 将src中的内容复制到dest中
List dest = Arrays.asList(new Object[src.size()])

38.IO流

抽象基类字符流字节流
输入流InputStreamReader
输出流OutputStreamWriter

FileWriter 写入时,若文件不存在,则会创建文件,

若文件存在,如果使用的是new FileWriter(file)构造器,则会对文件进行覆盖,如果使用new FileWriter(file, true)则会对原有文件进行追加

分类字节输入流字节输出流字符输入流字符输出流
访问文件FileInputStreamFileOutputStreamFileReaderFileWriter
缓冲流BufferedInputStreamBufferedOutputStreamBufferedReaderBufferedWriter
转换流InputStreamReaderOutputStreamWriter

缓冲流是包在节点流的外面。

InputStreamReader:实现字节输入流 —> 字符输入流,(解码)

OutputStreamWriter:实现字符输出流 —> 字节输出流,(编码)

对象流:1. ObjectInputStream

​ 2.ObjectOutputStream

作用:把对象存入到文件中保存起来。自定义的类要想存入文件中,必须保证可序列化。需满足以下两个条件:

(1)实现 Serializable 接口

(2)定义一个 private static final long serialVersionUID = 23313113131L

(3)不能序列化static和transient修饰的成员变量


RandomAccessFile(随机存储文件流)

(1)既可以作为输入流也可以作为输出流,直接继承于Object类

(2)作为输出流时,若文件不存在会自动创建,若存在则会从头覆盖源文件中的内容,有多少覆盖多少

(3)r:只读;rw:读写;

(4)rafe(int i):可以把(指针)切换到指定的位置

39.网络编程

39-1.IP

IP对应于java中的InetAddress类,实例化该类可以使用:getByName(String host) / getLocalHost().

两个常用方法:getHostName() – getHostAddress()

40.反射

1.获取Class实例的四种方法
  • 调用运行时类的.class属性

    Class c1 = Person.class;

  • 通过运行时类的对象,调用getClass()
    Person p1 = new Person();
    Class c2 = p1.getClass();

  • 调用Class的静态方法:forName(String classPath)
    Class c3 = Class.forName(“写类的路径”)

此时的c1,c2,c3都指向的是同一个地址,只是获取方式不同。

2.Properties读取配置文件
public void test2() throws Exception {
        Properties properties = new Properties();
//        方式一:这种方式读取的文件默认在module下,若文件在src中注意写清楚
//        FileInputStream fis = new FileInputStream("src//jdbc.properties");
//        properties.load(fis);

//        方式二:这种方式读取的文件默认在src下
        ClassLoader classLoader = FileReadTest.class.getClassLoader();
        InputStream is = classLoader.getResourceAsStream("jdbc.properties");
    
        properties.load(is);

        String name = properties.getProperty("name");
        String sex = properties.getProperty("sex");
        System.out.println("姓名:" + name + ", 性别:" + sex);
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b1xyaIRE-1666177889144)(…/…/AppData/Roaming/Typora/typora-user-images/1654418754583.png)]

3.通过反射,创建运行时类的对象
public class ClassTset {
    @Test
    public void test1() throws Exception {
        Class<Person> aClass = Person.class;
        Person person = aClass.getConstructor(int.class,String.class).newInstance(20,"夜兰");
        System.out.println(person);

    }
4.获取运行时类的属性结构

Class clazz = Class.forName(“”)

Field[] fields = clazz.getFields()

获取当前运行时类及其父类中声明为public权限的属性

Field[] fields = clazz.getDeclaredFields()

获取当前运行时类中的所有属性,不包括父类中的。方法类似。

for (Field f : fields){
    //获取属性的权限修饰符
    int i = f.getModifiers();
    System.out.print(Modifier.toString(i));
    //获取属性的数据类型
    Class type = f.getType();
    System.out.print(type.getName());
    //获取属性的名字
    String fName = f.getName();
}
5.操作运行时类的属性
//1.获取运行时类的对象

Class clazz =  Person.class;

Person p = clazz.getConstructor().newInstance();

//2.获取运行时类中指定的属性

Field name = clazz.getDeclaredField("name");

//3.保证当前属性是可访问的

name.setAccessible(true);

//4.对属性操作

name.set(p,"Tom");
6.操作运行时类的方法
//1.
Class clazz =  Person.class;

Person p = clazz.getConstructor().newInstance();

//2.参数一:指明获取的方法名称    参数二:指明方法的形参列表

Method method = clazz.getDeclaredMethod("show", String.class);

method.setAccessible(true);

//3.参数一:方法的调用者     参数二:给方法形参赋值的实参
// invoke() 返回值就是原方法的返回值
Object ReturnValue = method.invoke(p, "CHN");

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bGXnQ45R-1666177889144)(D:/HONOR Share/Screenshot/capture_20220606110205359.bmp)]

41. Lambda

1.语法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T5lKZhWl-1666177889145)(…/…/AppData/Roaming/Typora/typora-user-images/1654675967861.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5uw3BAom-1666177889145)(…/…/AppData/Roaming/Typora/typora-user-images/1654677626859.png)]

使用依赖于函数式接口(只含有一个抽象方法的接口)

42.Stream API

1.Stream的实例化
public class StreamTest {
    //方式一:通过集合
    @Test
    public void test1(){
        List<String> list = new ArrayList<String>();
        //返回一个顺序流
        Stream<String> stream = list.stream();
        //返回一个并行流
        Stream<String> parallelStream = list.parallelStream();
    }

    //方式二:通过数组
    @Test
    public void test2(){
        //调用Arrays的stream()
        int[] array1 = new int[]{1,2,3,4,5};
        IntStream stream = Arrays.stream(array1);
    }

    //方式三:通过Stream的of()
    @Test
    public void test3(){
        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
    }
}
2.Stream的中间操作
2.1筛选与切片
 @Test
    public void test4(){
        List<Integer> list = new ArrayList();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        list.add(6);
        Stream<Integer> stream = list.stream();
        //filter(Predicate p)  接受lambda,从流中排除某些元素
        stream.filter(x -> x > 2).forEach(System.out::println);

        //limit(n)   截断流,使其元素不超过n
        list.stream().limit(3).forEach(System.out::println);

        //skip(n)    跳过元素,返回一个扔掉前n个元素的流。若流中元素不足n,则返回一个空流
        list.stream().skip(2).forEach(System.out::println);

        //distanct()  筛选     通过流所生成元素的hashcode()和equals()去除重复数据
        list.stream().distinct().forEach(System.out::println);

    }
2.2映射
@Test
    //map()
    //结果类似于[aa,bb[cc,dd]]
    public void test5(){
        List<String> list = Arrays.asList("aa", "bb", "cc", "dd");
        list.stream().map(s -> s.toUpperCase()).forEach(System.out::println);
    }

    @Test
    //flatMap()
    //结果类似于[aa,bb,cc,dd]
    public void test6(){
        List<String> list = Arrays.asList("aa", "bb", "cc", "dd");
        list.stream().flatMap(StreamTest::stringToCharacter).forEach(System.out::println);
    }

    public static Stream<Character> stringToCharacter(String s){
        ArrayList<Character> arr = new ArrayList<Character>();
        for (Character str : s.toCharArray()){
            arr.add(str);
        }
        return arr.stream();
    }
2.3排序
 @Test
    //sorted()
    //sorted(Comparator com)      定制排序
    public void test7(){
        List<Integer> list = Arrays.asList(0, 12, 34, -12, 50, 90, -30);
        list.stream().sorted().forEach(System.out::println);
    }
3.终止操作
3.1匹配与查找
//allMatch()	---		检查是否匹配所有元素
boolean allMatch = list.stream().allMatch(num -> num > 20);

//anyMatch()	---		检查是否至少匹配一个元素

//noneMatch()	---		检查是否没有匹配的元素

//findFirst()	---		返回第一个元素

//findAny()		---		返回当前流中的任意元素

//count()		---		返回流中的总个数

//max(Comparator com)		返回流中最大值

//min(Comparator com)		返回流中的最小值

//forEach()		---		内部迭代
3.2归约
  @Test
    //reduce(T identity, BinaryOperator)
    //reduce(BinaryOperator)
    public void test8(){
        List<Integer> list = Arrays.asList(0, 12, 34, -12, 50, 90, -30);
        Integer reduce = list.stream().reduce(0, Integer::sum);
        System.out.println(reduce);
    }
3.3收集
  @Test
    //collect(Collector c)      将流转化为集合等别的形式
    public void test9(){
        List<Integer> list = Arrays.asList(0, 12, 34, -12, 50, 90, -30);
        List<Integer> collect = list.stream().filter(i -> i > 0).collect(Collectors.toList());
        System.out.println(collect);
    }

ring> list = Arrays.asList(“aa”, “bb”, “cc”, “dd”);
list.stream().flatMap(StreamTest::stringToCharacter).forEach(System.out::println);
}

public static Stream<Character> stringToCharacter(String s){
    ArrayList<Character> arr = new ArrayList<Character>();
    for (Character str : s.toCharArray()){
        arr.add(str);
    }
    return arr.stream();
}

##### 2.3排序

```java
 @Test
    //sorted()
    //sorted(Comparator com)      定制排序
    public void test7(){
        List<Integer> list = Arrays.asList(0, 12, 34, -12, 50, 90, -30);
        list.stream().sorted().forEach(System.out::println);
    }
3.终止操作
3.1匹配与查找
//allMatch()	---		检查是否匹配所有元素
boolean allMatch = list.stream().allMatch(num -> num > 20);

//anyMatch()	---		检查是否至少匹配一个元素

//noneMatch()	---		检查是否没有匹配的元素

//findFirst()	---		返回第一个元素

//findAny()		---		返回当前流中的任意元素

//count()		---		返回流中的总个数

//max(Comparator com)		返回流中最大值

//min(Comparator com)		返回流中的最小值

//forEach()		---		内部迭代
3.2归约
  @Test
    //reduce(T identity, BinaryOperator)
    //reduce(BinaryOperator)
    public void test8(){
        List<Integer> list = Arrays.asList(0, 12, 34, -12, 50, 90, -30);
        Integer reduce = list.stream().reduce(0, Integer::sum);
        System.out.println(reduce);
    }
3.3收集
  @Test
    //collect(Collector c)      将流转化为集合等别的形式
    public void test9(){
        List<Integer> list = Arrays.asList(0, 12, 34, -12, 50, 90, -30);
        List<Integer> collect = list.stream().filter(i -> i > 0).collect(Collectors.toList());
        System.out.println(collect);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值