面试答题(摘抄)

不知道为什么目录不支持跳转了,将就看啦😭

Java 中是如何支持正则表达式的

  • Java中的String类提供了支持正则表达式操作的方法,包括:matches()、replaceAll()、replaceFirst()、split()。此外,Java中可以用Pattern类表示正则表达式对象,它提供了丰富的API进行各种正则表达式操作

    import java.util.regex.*;
    
    public class RegExpTest {
        public static void main(String[] args) {
            String str = "成都市(成华区)(武侯区)(高新区)";
            Pattern p = Pattern.compile(".*?(?=\\()");
            Matcher m = p.matcher(str);
            if(m.find()){
                System.out.println(m.group());
            }
        }
    }
    

Java中jdk 和 jre 的区别

  • JDK 是Java 开发工具,它不仅提供了 Java 运行所需的JRE ,还提供了一系列的编译、运行等工具;JRE 只是 Java程序的运行环境,它最核心的内容就是 JVM.

变量及其作用范围

在 Java中,变量根据生成周期的不同可以分为静态变量、成员变量以及局部变量三种。

  • 静态变量就是指使用 static 修饰的变量,随着类的加载而加载
  • 成员变量是在类中没有使用 static 修饰的变量,它属于该类的某个实例,随着对象的加载而初始化,随着对象的回收而消失
  • 局部变量是定义在方法中的变量或方法中的参数,它们随着方法的调用而创造,随着方法的执行完毕而消失

Java 中equal 和 == 的区别

equal 和 “==” 两者都是表示相等的意思,但是它们相等的含义却有所区别

  • “==” 运算在基本数据类型的时候,比较它们实际的值是否相同;而用于比较引用类型的时候,则是比较两个引用的地址是否相等,是否指向同一对象
  • equal 方法是 java.lang.Object 的方法,它可以被重写,通过自定义的方法来判断两个对象是否相等。对于字符串 java.lang.String 类来说,它的 equal 方法用来比较字符串的字符序列是否完全相等

Java 提供了哪几种循环结构?它们各自的特点是什么?

Java 提供了三种循环结构,forwhiledo···while 语句。它们各自适用于不同的情况

  • for 循环使用于能确定循环次数的循环结构
  • while 则适用于单条语句的循环
  • do···while 在执行某段语句之后,再循环的时候

简述一下正则表达式及用途

  • 我们在编写处理字符串的程序时,经常会查找某些复杂规则字符串的需要,正则表达式就是在进行字符串匹配和处理时候最为强大的工具,测试字符串内的模式、替换文本、基于模式匹配从字符串中提取子字符串。

比较一下Java和JavaScript的区别

  • JavaScript 与Java是两个公司开发的不同的两个产品,Java是由Sun Microsystems公司推出的面向对象的程序设计语言;而JavaScript是Netscape公司的产品,JavaScript的前身是LiveScript;而Java的前身是Oak语言。

    1.基于对象和面向对象:Java是真正的面向对象语言;JavaScript是脚本语言

    2.解释和编译:Java的源代码在执行之前,必须经过编译。JavaScript是一种解释性编程语言。


&与&&的区别

  • &运算符有两种用法:(1)按位与;(2)逻辑与。&&运算符是短路与运算。逻辑与跟短路与的差别是非常巨大的,虽然二者都要求运算符左右两端的布尔值都是true整个表达式的值才是true。&&之所以称为短路运算是因为,如果&&左边的表达式的值是false,右边的表达式会被直接短路掉,不会进行运算。很多时候我们可能都需要用&&而不是&,例如在验证用户登录时判定用户名不是null而且不是空字符串,应当写为:username != null &&!username.equals(""),二者的顺序不能交换,更不能用&运算符,因为第一个条件如果不成立,根本不能进行字符串的equals比较,否则会产生NullPointerException异常。

String 和StringBuffer的区别

  • String类提供了数值不可改变的字符串,StringBuffer类提供的字符串可进行修改。

Int 和 Integer 的区别

  • Java提供了两种不同的类型:引用类型和原始类型(内置类型)。Int 是Java的原始数据类型,Integer 是Java为 Int 提供的封装类。

数组(Array)和列表(ArrayList)的区别?什么时候应该使用Array而不是ArrayList?

区别:

  • Array 可以包含基本类型和对象类型,ArrayList 只能包含对象类型

  • Array 大小是固定的,ArrayList 的大小的动态变化的

  • ArrayList 提供了更多的方法和特性,比如:addAll(),iterator()等等

    对于基本类型数据,集合使用自动装箱来减少编码的工作量。但是,当处理固定大小的基本数据类型的时候,这种方式比较慢


什么是值传递和引用传递

  • 值传递是对基本型变量而言的,传递的是该变量的一个副本,改变副本不影响原变量

  • 引用传递一般是对于对象型变量而言的,传递的是该对象地址的一个副本,并不是原对象本身。所以对引用对象操作会同时改变原对象

    一般认为,Java内的传递都是值传递


Java8 的新特性

  • Lambda 表达式--Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)

  • 方法引用--方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法和构造器。与lambda 联合使用,方法引用可以使语言的构造更紧凑简介,减少冗余代码

  • 默认方法--默认方法就是一个在接口里面有了一个实现的方法

  • 新工具--新的编译工具,比如:Nashorn 引擎 jjs 、 类依赖分析器jdeps

  • Stream-API--新添加的Stream API(java.util.stream)把真正的函数式编程风格引入到Java中

  • Date Time API--加强对日期与时间的处理

  • Optional 类--Optional 类已经成为Java8 类库的一部分,用来解决空指针异常


“==”符号比较的是什么

  • ”对比两个对象基于内存引用,如果两个对象的引用完全相同时,“”返回true,反之false。
  • “==”如果两边是基本类型,就是比较数值是否相等

访问权限修饰符

image
image


final 关键字怎么用?

  • 当 final 修饰一个类时,表明这个类不能被继承。final 类中的所有成员方法都会被隐式地指定为 final 方法
  • 对于 final 变量,如果是基本数据类型的变量,则其数值一旦被初始化之后就不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另外一个对象

hashCode() 和 equals() 方法的联系

  • 相等的对象必须具有相等的哈希码
  • 如果两个对象的 hashCode 相同,它们并不一定相同

什么是构造函数、什么是构造函数重载、什么是复制构造函数?

  • 当新对象被创建时,构造函数就会被调用。每一个类都有一个默认的构造函数
  • 构造函数重载和方法重载类似,可以为一个类创建多个构造函数,每个构造函数都有自己唯一得参数列表
  • Java 不会默认创建构造函数

重载(Overload)和重写(Override)的区别

  • 方法的重载和重写都是实现多态的方式,重载实现的是编译时的多态性,重写实现的是运行时的多态性。同名的方法如果有不同的参数列表(参数类型不同、参数个数不同)视为重载;重写要求子类与父类有相同的返回类型

Java 如何使用继承来重用代码?

  • Java 采用单继承制,使用 extend 关键字,通过继承后,子类就拥有了父类除私有方法外的所有成员,从而达到代码重用的目的,在继承过程中,可以使用重写来实现多态,让子类拥有自己独特的方法来实现自己的方式

简述 Java 中的多态

  • “多态” 按照字面意思来理解就是“多种形式,多种状态”。它的本质是发送信息给某个对象,让该对象来自行决定响应何种行为。通过将子类对象引用赋值给超类对象引用变量来实现多态的调用

接口和抽象类的区别

  • 抽象类是一种功能不完全的类,接口只是一个抽象方法声明和静态不能被修改的数据的集合,两者都不能被实例化。从某种意义上来说,接口是一种特殊形式的抽象类,在 Java 语言中,抽象类表示一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现多个接口

静态内部类

  • 使用 static 关键字修饰的内部类

    package abc
    class Outter{					//定义外部类 Outter
        static class inner{			//定义静态内部类 inner
            
        }
    }
    
    • 在外部类加载的时候,静态内部类也随之加载。由于静态内部类是静态的,所以它无法访问外部类的静态成员。静态内部类对于外部类来说,几乎是独立的,它可以在没有外部类对象的情况下,单独创造一个内部类的对象
  • 静态内部类相对于外部类来说,仅仅是包含关系,缩小了命名空间,完整类名中多了一个外部类的名称。本质上是两个独立的类, JVM 也不知道它们两个有包含关系


StringBuffer 和 StringBuilder 存在的作用是什么?

  • 在 Java 程序中,如果有大量拼接字符串的需要,应该使用 StringBuffer 和 StringBuilder 类,它们可以避免不必要的 String 对象的产生,以提高程序的性能。它们两者的作用类似,而 StringBuilder 线程是不安全的

如何输出反转后的字符串

class Untitled {
	public static void main(String[] args) {
		
		String s = "If you are always there I will always love you";
		System.out.println("原始的字符串:" + s);
		
		System.out.println("反转后的字符串:");
		for (int i =s.length(); i>0;i--){
			System.out.print(s.charAt(i-1));
		}
		
	}
}

这是常用的方法,反向取出每个位置的字符串,然后将它们打印到控制台上,但是 Java 是一种提供多种现成共能得语言,使用 StringBuffer 可以更容易实现

class Untitled {
	public static void main(String[] args) {
		
		String s = "If you are always there I will always love you";
		System.out.println("原始的字符串:" + s);
		
		System.out.println("反转后的字符串:");
		
		StringBuffer sb = new StringBuffer(s);
		System.out.print(sb.reverse().toString());
	}
}

如何拷贝数组中的数据

拷贝数组应该使用 System.arraycopy() 方法

public class ArrayCopy{
    public static void main(String[] args){
        int[] arr = new int[]{1,2,3};
        int[] arr2 = new int[3];
        System.arraycopy(arr,0,arr2,0,arr.length);      //深拷贝数组

        arr2[2] = 7;
        for(int i:arr){
            System.out.println(i);      //1 2 3
        }
        for(int i:arr2){
            System.out.println(i);      //1 2 7
        }
    }
}

二维数组的长度是否固定

public class MultiDiArray {
    public static void main(String[] args) {
        int[][] arr = new int[3][];
        arr[0] = new int[]{4};
        arr[1] = new int[]{4, 5};
        arr[2] = new int[]{2, 3, 4};

        for (int[] a : arr) {
            for (int i : a) {
                System.out.print(i + "\t");
            }
            System.out.println();
        } //4	
		  //4	5	
		  //2	3	4	
    }
}
  • 长度不固定。Java 数组的长度是可以动态变化的,可以任意拓展数组的维度,每一维度的元素个数都可以不尽使用

什么是集合

  • 集合是用来也只能用来存储其它对象的对象,代表了一种底层结构,用于拓展数组的功能。集合框架由一系列的接口和实现类组成,基本包括:
    • 列表(List)
    • 集合(Set)
    • 映射(Map)

什么是迭代器

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

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

        List<String> list = new ArrayList<>();

        list.add("a");
        list.add("b");

        Iterator<String> it = list.iterator();  //得到list的迭代器
        //调用的迭代器的 hasNext() 方法,判断是否有下一个元素
        while(it.hasNext()){
            System.out.println(it.next());
        }
    }
}
  • 迭代器,提供一种访问一个集合对象中各个元素的途径,同时又不需要暴露该对象的内部细节。Java 通过提供 Iterable 和 Iterator 两个接口来实现集合类的可迭代性。迭代器主要的用法就是,首先用 hasNext() 作为循环条件;再用 next() 方法得到每一个元素;最后再进行相关操作

比较器

  • 对于 Comparable 接口来说,它往往是进行比较类需要实现的接口,它仅包含有一个 compareTO 方法,只有一个参数,返回值为 int 型数据。返回值大于0时,则表示本对象大于参数对象,小于0时,则表示本对象小于参数对象,等于0则表示两者相等

    public class ComparableUser implements Comparable{
    
        private String id;
        private int age;
    
        public ComparableUser(String id, int age) {
            this.id = id;
            this.age = age;
        }
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public int compareTo(Object o) {
            return this.age - ((ComparableUser) o).getAge();
        }
    
        public static void main(String[] args) {
            ComparableUser user1 = new ComparableUser("u01",25);
            ComparableUser user2 = new ComparableUser("u01",26);
    
            if(user1.compareTo(user2)>0){
                System.out.println("用户1大于用户2");
            }else if(user1.compareTo(user2)<0){
                System.out.println("用户1小于用户2");
            }else{
                System.out.println("用户1和用户2一样大");
            }
        }
    }
    
  • Comparator 也是一个接口,它的实现者被称为比较器,它包含一个 compare() 方法,有两个参数,返回值与 Comparable() 的compareTo() 方法一样。不同之处就是 Comparator 接口一般不会被集合元素类所实现,而是单独实现或者用匿名内部类的方式实现

    从Java5.0开始,Comparable 和 Comparator 接口都支持泛型,不需要进行类型转换

    import java.util.Comparator;
    
    public class User {
        private String id;
        private int age;
    
        public User(String id, int age) {
            this.id = id;
            this.age = age;
        }
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        /*测试方法*/
        public static void main(String[] args) {
            User u1 = new User("u01", 24);
            User u2 = new User("u02", 24);
            Comparator comp = new UserComparator();
    
            int rst = comp.compare(u1, u2);
            if (rst > 0) {
                System.out.println("用户1大于用户2");
            } else if (rst < 0) {
                System.out.println("用户1小于用户2");
            } else {
                System.out.println("用户1等于用户2");
            }
        }
    }
    
    class UserComparator implements Comparator<User> {
    
        @Override
        public int compare(User o1, User o2) {
            User u1 = (User) o1;
            User u2 = (User) o2;
            return u1.getAge() - u2.getAge();
        }
    }
    
  • 比较器是把集合或数组的元素强行按照指定方法进行排序的对象,它是实现了 Comparator 接口的实例。如果一个集合元素的类型是可比较的(实现了 Comparable 接口),那么它就具有默认的排序方法,比较器则是强行改变它默认的比较方式来进行排序。


Vector 和 ArrayList 的区别

public class ListTest {
    public static void main(String[] args) {
        Vector<String> v = new Vector<String>();
        v.add("hello");
        v.remove("hello");
        System.out.println(v.size());

        ArrayList<String> al = new ArrayList<String>();
        al.add("world");
        al.remove("world");
        System.out.println(al.size());
    }
}
  • Vector 是线程安全的,因为它操作元素的方法都是同步方法,而 ArrayList 则不是。开发过程中根据需求进行选择,如果需要保证线程安全的地方则需要使用 Vector,而不必要的时候可以使用 ArrayList ,因为它的效率会高一些

集合使用泛型有什么好处?

  • 集合使用泛型后,可以达到元素类型目的明确,避免了手动转换类型的过程,也让开发者明确了容器保存的什么类型的数据

如何对集合中的元素进行排序

  • 如果列表中的元素都是相同类型的,并且这个类实现了 Comparable 接口,可以简单的调用 Collections.sort(),如果这个类没有实现 Comparator,就可以传递一个 Comparator 实例作为 sort() 的第二个参数进行排序。

异常类

  • Throable
  • Error:系统无法控制的严重异常。例如内存不足
  • RunningException:
    • 空指针异常、数组下标越界异常、算数异常、文件找不到异常、类型转换异常
  • 异常的处理:
    • throw:用在方法体内,抛出异常对象,可以抛出一个
    • throws:用在方法体外,异常类,可以多个

IO 流


线程的实现方式

  • 继承 Thread 类
  • 实现 Runnable 接口
  • 通过 Callerble 实现
  • 线程的状态:
    • 新建--就绪--运行--死亡
    • sleep--休眠--休眠后进入就绪状态
    • join--加入--等待状态
  • 线程的通信:
    • wait() -- 释放锁 -- 等待状态
    • notify -- 唤醒一个释放锁等待状态的线程 -- 被唤醒的线程进入就绪状态 -- 准备抢占 cpu
    • notifyAll() -- 唤醒所有释放锁等待状态的线程 -- 被唤醒的线程进入就绪状态 -- 准备抢占 cpu

目录和文件操作

public class FileDirTest {
    public static void main(String[] args) {
        File file = new File("D:\\notepad++\\readme.txt");
        if (!file.exists()) {     //判断是否已经存在
            try {
                file.createNewFile();   //创建新文件
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        File dir = new File("D:\\javaDemo\\TestDemo\\src\\BoXueGu");
        if (dir.isDirectory()) {      //判断是否为目录
            String[] files = dir.list();    //调用list()方法获取它的文件
            for (String s : files) {
                //用目录和文件名生成file对象
                File f = new File(dir.getPath() + File.separator + s);
                if (f.isFile()) {
                    System.out.println("file:" + f.getName());
                } else if (f.isDirectory()) {
                    System.out.println("dir:" + f.getName());
                }
            }
        }
    }
}

  • isDirectory() 和 isFile() 方法:用于检查该 File 对象所代表的是目录还是普通文件
  • createNewFile() 方法:创建新文件,采用 File 对象所存储的路径和文件名进行创建
  • list() 方法:用于目录,得到目录下所有的文件名,类型为字符串数组
  • getName() 方法:得到文件名,不包含路径
  • delete() 方法:删除文件

随机存储文件

  • 使用 RandomAccessFile 的思路主要有一下几点:

    • 用 length() 方法获取到文件的内容长度
    • 用 seek() 方法随机的到达任何需要存取数据的地方
    • 调用 read() 方法获取当前位置的数据,用 write() 方法写入数据
    • 完成调用后,调用 close() 关闭文件
    public class RanAccFileTest {
        public static void main(String[] args) {
            try {
                RandomAccessFile file = new RandomAccessFile("D:\\迅雷下载\\2021年最新鸡活方案汇总\\必看方案说明.txt", "rw");
                for (int i = 0; i < file.length(); i++) {
                    byte b = (byte) file.read();
                    char c = (char) b;
                    if (c == '0') {
                        file.seek(i);
                        file.write('c');
                    }
                }
                file.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    }
    

字节流的处理方式

  • 字节流最大的特点,就是每次的输出和输入都是一个字节。因此,它的主要应用在最原始的流的处理上,如内存缓存操作、文件复制

    public class FileCopy {
        public static void main(String[] args) throws IOException {
    
            InputStream ist = new FileInputStream("D:\\javaDemo\\abc.txt");
            OutputStream ost = new FileOutputStream("D:\\javaDemo\\ac.txt");
            byte[] by = new byte[1024];
            int len = 0;
            
            while ((len = ist.read(by)) != -1) {
                ost.write(by, 0, len);
            }
            ost.close();
            ist.close();
        }
    }
    
  • 字符流是由字节流包装起来的,它的输入和输出流类型包括 StringReader 和 StringWriter、BuffereredReader 和 BufferedWriter

    public class ReadTest {
        public static void main(String[] args) throws IOException {
            InputStream in = new FileInputStream("D:\\javaDemo\\abc.txt");
            InputStreamReader isr = new InputStreamReader(in, "utf-8");
    //InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\javaDemo\\abc.txt"));
            BufferedReader br = new BufferedReader(isr);    //创建Reader
            StringBuffer sb = new StringBuffer();           //临时保存字符内容
            String str = null;
    
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            System.out.println("abc.txt:"+sb);
            br.close();
        }
    }
    

序列化和反序列化

  • 序列化,又称“串化”,本质上就是把对象中的数据按照一定的规则,变成一系列的字节数据,然后再把这些字节数据写入到流中。而反序列化的过程相反,先读取字节数据,然后再重新组装成 Java 对象所有需要进行序列化的类,都必须实现 Serializable 接口,必要时还需要提供静态的常量 seriaViersionUID

序列化最重要的作用:在传递和保存对象时,保证对象的完整性和可传递性。对象转换为有序字节流,以便于在网络上传输或者保存在本地文件中

反序列化最重要的作用:根据字节流中保存的状态及描述信息,通过反序列化重建对象

class student implements Serializable {
    //序列化ID
    private static final long serialVersionUID = -4526146658500473902L;
    private String name;
    private int age;

    public student() {
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
//建议学生类新建一个Java文件进行编写,我只是为了方便,对于序列化ID不知道怎么生成的可以自行百度,需要在 idea 里面勾选一个选项即可


public class SerialTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        student stu = new student();
        stu.setAge(20);
        stu.setName("小明");
        //创建对象输出流
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\javaDemo\\ac.txt"));
        oos.writeObject(stu);
        oos.close();
        //创建一个对象输入流
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\javaDemo\\ac.txt"));
        //读出序列化的对象
        Object obj = ois.readObject();
        //进行类型转换
        student stu1 = (student) obj;
        //打印在控制台,检查序列化及反序列化是否成功
        System.out.println("stu name is" + stu1.getName());
        System.out.println("stu age is" + stu1.getAge());

    }
}

对于对象的输出和输入,Java 的 I/O 体系中主要提供了 ObjectOutputStream 和 ObjectInputStream 两个类:

  • 让需要序列化的类实现 java.io.Serializable 接口
  • 提供静态的 long 型的常量 serialVersionUID
  • 如果是序列化对象,则用一个输出流创建一个ObjectOutputStream对象,然后调用 writeObject() 方法
  • 如果是反序列化,首先使用一个输入流创建一个 ObjectInputStream 对象。然后调用 readObject() 方法,得到一个 Object 类型的对象。最后再做类型的强制转换
  • 最后关闭流

多线程

  • 多线程是为了使得多个并行的工作可以完成多项任务,以提高系统的效率。多线程进制下的线程彼此之间独立,比较容易共享数据,通过并发执行的方式来提高程序的效率和性能,使用多线程能带来以下好处:
    • 使用线程可以把占据长时间的程序中的任务放到后台去处理
    • 用户界面可以更加吸引人(自己体会)
    • 程序的运行速度可能加快,人多力量大
    • 在一些等待的任务实现上如果用户输入、文件读写和网络传输数据等,线程就比较空闲了。在这种情况下可以释放一些资源,如内存占用

1、如何让一个类成为线程类

  • 一个是实现 java.lang.Runnable 接口,另一个就是继承 java.lang,Thread 类

    public class RunnTest implements Runnable{
        public void run(){
            System.out.println('thread running.....');
        }
    }
    class ThreadTest extends Thread{
        public void run(){
            System.out.println("thread running.....");
        }
    }
    
    • 线程类继承自 Thread 则不能继承其它类,而 Runnable 接口可以
    • 线程类继承自 Thread 相对于 Runnable 来说,使用线程的方法更方便些
    • 实现 Runnable 接口的线程类的多个线程,可以更方便的访问同一变量,而 Thread 类则需要内部类来替代

2、如何使用 synchronized 实现线程同步

  • synchronized 的工作原理:每一个对象都有一个线程锁,synchronized 可以用任何一个对象的线程锁来锁住一段代码,任何想进入该段代码的线程都要在解锁后菜鸟继续执行,否则进入等待状态

    class MyThread extends Thread {
        public static int index;                    //静态变量
        public static Object obj = new Object();    //用任意一个对象来加锁
    
        public void run() {
            synchronized (obj) {                      //为冲突加上同步代码块
                for (int i = 0; i < 100; i++) {
                    System.out.println(getName() + ":" + index++);
                }
            }
        }
    }
    
    public class SyncTest {
        public static void main(String[] args) {
            new MyThread().start();
            new MyThread().start();
            new MyThread().start();
            new MyThread().start();
        }
    }
    

    synchronized 关键字代表要为某一段代码加上一个同步锁,这样的锁是绑定在某一个对象上边的。如果是同步代码块,需要为该synchronized 关键字提供一个对象的引用;如果是同步方法,只需要加一个 synchronized 关键字修饰


posted @ 2021-11-01 19:52  这阵风是晚安  阅读(109)  评论(0编辑  收藏  举报