知识点汇总4

178 阅读15分钟

一、基础

1、JVM、JRE、JDK有什么区别?

  • JVM = Java虚拟机,跑Java程序的。
  • JRE = JVM + 核心类库,什么是核心类库:比如基本数据类型、函数、线程、异常处理类等等。
  • JDK = JRE + 编译、打包工具等。

如果要跑Java程序要用JRE,如果要开发Java程序用JDK。

img

2、switch 是能作用在哪里?

byte b1 = 1;            //可以

short s1 = 2;           //可以

int i1 = 4;             //可以

long l1 = 8;            //不可以

float f1 = 4.0f;        //不可以

double d1 = 8.0;        //不可以

boolean flag = true;    //不可以

char c1 = 'c';          //可以

String st1 = "测试";    //可以

EnumTest failure = EnumTest.FAILURE;    //可以

switch (XXXX){
	...
}

例子说明:

  • byte、short、int、char(Java5之前就可以),Enum对象可以(Java5以后可以),String字符串可以(Java7以后可以)
  • long、float、double、boolean都不行

3、Math.round(11.5) 等于多少?

参数 + 0.5 取小就对了。

double d1 = 10.7;
double d2 = 10.3;
double d3 = -9.4;
double d4 = -11.6;

System.out.println(Math.round(d1));     //11
System.out.println(Math.round(d2));     //10
System.out.println(Math.round(d3));     //-9
System.out.println(Math.round(d4));     //-12

4、short s1 = 1; s1 = s1 + 1;有错吗? short s1 = 1; s1 += 1;有错吗?

知道两点即可:

  • 普通的数字认定为int类型
  • +=可以自动转换类型

那么s1 = s1 + 1,是short类型 + int类型,结果是int类型,肯定不对;

而 += 在运算完之后进行类型转换,所以可以。

5、访问修饰符 public,private,protected,以及不写(默认)时的区别?

可以这样理解:代码 看作 钱。

  • public:公用的钱--->慈善基金,大家都可以用
  • protected:受法律保护的钱--->遗产,遗产是自己、妻子、儿子的,也就是本类、同包、子类都能用
  • default:默认的钱--->家庭财产,一般也就是夫妻共用的钱,同包才能用,default也叫包访问权限
  • private:私有的钱--->小金库,媳妇也不愿意给用
image-20211118115039630

6、&和&&的区别?

  • &指的是按位与,进行运算用的,只有当两个二进制位都为1,才为1,其他情况为0。
System.out.println(5 & 3);	//1

5用二进制 101 表示,3用二进制 011 表示(简化版本,其余位的0没写),101和011按位对照,只有最后1位都是1,那么最后结果就是001,换算回来也就是1。

  • &也可以指逻辑与,用于判断的时候。
if (5 == 5 & 5 > 3){
    System.out.println("5等于5,且大于3");
}else{
    System.out.println("说的不对");
}
  • &&指的是短路与,就是上面多个条件判断,只有都是true才为true,如果是短路与,如果第一个为false了,后面就不判断了,首先&&的性能要好一点点,但是判断后面如果有计算的话,肯定就没办法执行了。
int num = 10;
if (num == 9 & ++num == 10){
}
System.out.println(num);	//11
int num = 10;
if (num == 9 && ++num == 10){
}
System.out.println(num);	//10

7、final关键字的作用?

总之都是最终的意思,也就是不能修改:

  • 类上,不能继承 --->不让改了继承也没什么用了
  • 方法上,不能覆盖--->同理,方法也不让你改了
  • 变量上,不能修改--->变量的引用不能改了,值可以改,但必须初始化,系统不给你赋默认值,要不用在企业上随手写个final,你忘了赋值又不好修改,造成损失了,到时候Oracle公司不背这个锅。

8、final、finally、finalize的区别?

final刚才说了

finally用在try...catch...finally中,保证不管是不是异常情况下,我希望走完的代码都能走完,比如一些资源类的东西。

finally在return下可不可以执行。

可以的:

public static void main(String[] args) {
    try{
        System.out.println("Hello World");
        return;
    }catch (RuntimeException e){
        e.printStackTrace();
    }finally {
        System.out.println("能不能执行呢?");
    }
}

//控制台输出
Hello World
能不能执行呢?

怎么才不执行呢?

在使用了System.exit(0);代码以后就不执行了。

public static void main(String[] args) {
    try{
        System.out.println("Hello World");
        //退出JVM
        System.exit(0);
        System.out.println("这里也不知道能不能执行");
    }catch (RuntimeException e){
        e.printStackTrace();
    }finally {
        System.out.println("能不能执行呢?");
    }
}

//控制台输出
Hello World

finalize关键字,看看老祖宗Object:

protected void finalize() throws Throwable { }

当垃圾回收器发现某个对象不再被引用了,系统会调用finalize方法进行回收,可以是呀Sytem.gc()去建议垃圾回收器回收。

public class Test {
    public static void main(String[] args) throws Throwable {
        Test test = new Test();
        test = null;

        System.gc();
        Thread.sleep(1000);
        System.out.println("退出...");
    }

    @Override
    protected void finalize() throws Throwable {
        System.out.println("收拾完啦");
    }
}

//控制台输出
收拾完啦
退出...

9、this和super的用法?

this可以用来对 类的成员变量和形参同名时 做区分。

this还可以用于构造方法中。

public class Dog {
    private String name;
    private Integer age;

    public Dog(){
    }

    public Dog(String name){
        this();
        this.name = name;
    }

    public Dog(String name,Integer age){
        this(name);
        this.age = age;
    }

    public static void main(String[] args) {
    }
}

super是指向父类的指针。使用方式和上面类似。

10、static如何使用?

  • 不创建对象,直接可以调用属性和方法。
private static String name;

public static void main(String[] args) {
    System.out.println("2");
}
  • 用于静态代码块,一个类中可以有多个静态代码块,并且静态代码块会按顺序执行,有的对象可能不希望有多个,那么使用static修饰,保证它只有一个,**这个对象会在类初始化的时候创建,**并且每次使用都用这个对象
static{
    Dog dog = new Dog();
    System.out.println("1");
}

注意:代码块、静态代码块

静态代码块是在main方法执行前执行,并且只执行一次

代码块是构造对象的时候执行,每调用一次构造方法就执行一次,不管是有参还是无参

而且一个类有多个静态代码块和代码块,它们会按照顺序执行

public class Dog {
    private String name;

    public Dog(String name) {
        this.name = name;
        System.out.println("执行有参构造方法");
    }

    static{
        System.out.println("初始化静态代码块1");
    }

    static{
        System.out.println("初始化静态代码块2");
    }

    {
        System.out.println("初始化代码块1");
    }

    {
        System.out.println("初始化代码块2");
    }

    public Dog() {
        System.out.println("执行无参构造方法");
    }

    public static void main(String[] args) {
        Dog dog1 = new Dog();
        Dog dog2 = new Dog("xiaohua");
        System.out.println("测试");
        Dog dog3 = new Dog();
    }


    static{
        System.out.println("初始化静态代码块3");
    }

    {
        System.out.println("初始化代码块3");
    }
}

//控制台输出
初始化静态代码块1
初始化静态代码块2
初始化静态代码块3
初始化代码块1
初始化代码块2
初始化代码块3
执行无参构造方法
初始化代码块1
初始化代码块2
初始化代码块3
执行有参构造方法
测试
初始化代码块1
初始化代码块2
初始化代码块3
执行无参构造方法

11、如何跳出当前的多重嵌套循环?

给循环起个名字,在里面用特定条件break 名字,即可在内存循环中跳出外层循环。

public class Test {
    public static void main(String[] args) {
        circle:
        for (int i = 1;i < 20;i++){
            for (int j = 1;j < 20;j++){
                if (i == 10){
                    break circle;
                }
                System.out.print(i + "<=>" + j + " ");
            }
            System.out.println();
        }
    }
}

二、面向对象

12、面向对象三大特征?

特征:封装、继承、多态

  • 封装:可以使用访问修饰符对对象的属性、方法进行控制,暴露一些想暴露的方法,限制一些不希望被他人操作的属性、方法。这样对象就可以操控对象来完成业务开发,不用担心会出现安全问题。
  • 继承:继承相当于使用了对象的公共部分。如果每次都创建类似的新类,一来太麻烦,二来耦合度太高了。Java提供了继承机制,让我们可以创建新的类来继承以前的类、抽象类和接口。
  • 多态:相当于使用了对象的特点,不同于父类的地方。任何对象都不可能一模一样,肯定会有它的差异,Java提供了父类型引用指向子类型对象的多态机制,这让我们调用代码更加灵活。编译阶段JVM只会看这个调用到的父类型是否满足要求,执行的时候才会看子类型。这样耦合度就非常小了。

13、什么是多态机制?

  • 多态机制:父类型引用指向子类型对象。这种方式在编译过程中,编译器只看父类型是否有这个方法,而这个对象具体属于哪个类,调用的具体是什么方法,编译器不关心,只是在运行期间,在真正去绑定实际的类及方法。
  • 如何实现的:非OOP的编程语言很多采用的是前期绑定的方式,也就是编译时就解析到这个对象的绝对地址,而OOP语言编译时只检查对象是否和方法匹配,具体属于哪个类、执行哪个方法则是在运行时才确定的。

14、面向对象的基本原则?(设计模式的原则)

原则解释
开闭原则对扩展开放,对修改关闭==>一个公司内部员工总是频繁调动不好,不如直接招募新人
里氏替换原则子类可以替代父类在程序中出现的任何地方==>对接的时候是部长对接,而实际是底下员工操作。实际操作的时候员工肯定是要能替换部长的职责的(实现是由子类实现的)
依赖倒转原则依赖于抽象,不依赖于具体实现==>和其他部分、领导对接的时候,是部长去对接,不依赖于手底下员工(派一个代表)
迪米特原则最少知道原则,只知道跟它相关的类和对象即可,其他不需要知道==>不需要你知道的不需要知道,程序里面知道太多,依赖就很多
单一职责原则每个类/接口提供单一职责==>公司也是,一个类干一个事儿,到时候处理任务也方便
接口分离原则给客户端提供多个小的接口,而不是一个通用接口==>客户找到公司了,公司没有系统的部门,乱成一锅粥,不知道具体找谁,不利于扩展
组合复用原则要尽量使用类的合成复用,尽量不要使用继承==>想让A部门去干一份工作,A部门干不了,B部门能干,那么先把B的员工纳入A部门就行了,没必要让A部门员工学会B部门的工作

15、接口和类的区别?

相同点:

  • 都不能实例化对象
  • 都是用来被其他类继承的
  • 都含有抽象方法,都需要子类实现这些方法

不同点:

参数抽象类接口
声明抽象类使用abstract关键字声明接口使用interface关键字声明
实现子类使用extends关键字来继承抽象类.如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现子类使用implements关键字来实现接口。它需要提供接口中所有声明的方法的实现
构造器抽象类可以有构造器接口不能有构造器
访问修饰符抽象类中的方法可以是任意访问修饰符接口方法默认修饰符是public。并且不允许定义为 private 或者 protected
多继承一个类最多只能继承一个抽象类一个类可以实现多个接口
字段声明抽象类的字段声明可以是任意的接口的字段默认都是 static 和 final 的

16、内部类有哪些?

静态内部类、成员内部类、局部内部类、匿名内部类。

静态内部类

静态内部类就是在类的内部创建的静态类,内部类可以访问到外部的静态变量,但是非静态变量是访问不到的。能访问,但只能访问一点点。

public class Test {
    private static String test_name = "test_name";

    static class StaticInnerClass{
        public String getOuterName(){
            return test_name;
        }
    }

    public static void main(String[] args) {
        StaticInnerClass innerClass = new StaticInnerClass();
        System.out.println(innerClass.getOuterName());
    }
}

成员内部类

就是在类中创建一个不带static的内部类,而外部的静态变量、非静态变量,内部类都可以访问的到。

public class Test1 {
    private static String static_name = "static_name";
    private String non_static_name = "non_static_name";

    class InnerClass{
        public String getStaticName(){
            return static_name;
        }

        public String getNonStaticName(){
            return non_static_name;
        }
    }

    public static void main(String[] args) {
        Test1 test1 = new Test1();
        InnerClass innerClass = test1.new InnerClass();
        System.out.println(innerClass.getStaticName());
        System.out.println(innerClass.getNonStaticName());
    }
}

局部内部类

就是在类方法中创建一个类,静态方法的内部类不能访问非静态方法,非静态方法的内部类都可以访问。

public class Test2 {
    private static String static_name = "static_name";
    private String non_static_name = "non_static_name";

    public static void testInnerClass1(){
        class InnerClass{
            public String getStaticName(){
                return static_name;
            }
        }

        InnerClass innerClass1 = new InnerClass();
        System.out.println(innerClass1.getStaticName());
    }

    public void testInnerClass2(){
        class InnerClass{
            public String getStaticName(){
                return static_name;
            }

            public String getNonStaticName(){
                return non_static_name;
            }
        }

        InnerClass innerClass2 = new InnerClass();
        System.out.println(innerClass2.getStaticName());
        System.out.println(innerClass2.getNonStaticName());
    }

    public static void main(String[] args) {
        Test2 test2 = new Test2();
        test2.testInnerClass2();
        testInnerClass1();
    }
}

匿名内部类

一般是指不打算重用而要实现一个接口才这么使用。而这个方式是最常见的。

public class Test3 {
    public static void main(String[] args) {
        new Interfaces() {
            @Override
            public String sayHello() {
                return "Hello World";
            }
        };
    }
}

interface Interfaces {
    String sayHello();
}

17、局部内部类和匿名内部类访问局部变量的时候,为什么变量必须要加上final?

new Mouse()的匿名内部类中,有个caught()方法,这个方法引用了getMouse()方法的局部变量。

局部变量在方法结束后就会自动回收掉了,而mouse对象则不一定,可能会在其他地方被引用,导致长时间不会被回收。

所以count局部变量可能已经被回收了,而mouse对象还在使用count参数,肯定是不行的。那么必须加上final来保证一致性。

注意在JDK1.8之后,这样写代码已经不报错了,如果想测试尝试下载jdk1.7测试。

网址:Java Platform, Standard Edition 7 Reference Implementations

public class Cat {
    public void getMouse(){
        int count = 20;
        new Mouse() {
            @Override
            public void caught() {
                System.out.println(count + "只老鼠被抓到了");
            }
        };
    }
}

interface Mouse{
    void caught();
}

18、重载和重写的区别?

  • 重载:一般是同一个类中的各个方法,要求同名 + 不同形参(方法标识,方法标识要求唯一),访问修饰符和返回值不做要求。不同形参是指,形参数量、顺序、类型不同就算。
  • 重写一般是指有继承关系的两个类,子类覆盖了父类的方法,这里面要求方法返回值、方法名、形参都一样,而且子类不能比父类更封闭,子类型抛异常不能比父类抛的更多。也就是儿子应该更能干一点,不能比爸爸更宅、不能比爸爸问题更多。

19、== 和 equals 的区别是什么?

==相当于是比较两个对象是否相等,也就是它们的内存地址是否相等。而equals其实和它是一样的,但是equals方法可以重写,重写以后就可以比较它们的值了。

三、包、IO、类、异常

20、Java中有哪些常用的包?

  • java.lang:系统的基础类
  • java.io:用于io处理的包
  • java.net:网络相关的包
  • java.util:系统辅助类,特别是集合的包
  • java.sql:用于数据库操作的包

21、java 中 IO 流分为几种?

  • 按照流向:输入流、输出流
  • 按照操作单元:字节流、字符流
IO-操作方式分类

22、BIO,NIO,AIO 有什么区别?

  • BIO:Block IO,也叫同步阻塞式IO,就是最普通的IO,处理并发效率比较低。
  • NIO:NO IO,也叫同步非阻塞式IO,客户端和服务器使用channel通信,实现多路复用
  • AIO:Asychronous IO,也叫异步非阻塞式IO,异步IO基于事件和回调机制。

23、Files的常用方法都有哪些?

Files的常用方法如下:

增:

  • createDocument():创建文件夹
  • createFile():创建文件
  • copy():复制文件

删:

  • delete():删除

改:

  • move():移动文件
  • write():写入文件

查:

  • exists():查看文件是否存在
  • size():查看文件数量
  • read():读取文件

24、异常的分类?

  • 异常Exception:代码级别的问题,可以被捕获并进行相应的处理。
  • 错误Error:JVM级别的严重错误,出现Error会让程序进入不可恢复的状态。
在这里插入图片描述
  • 运行时异常,也叫做非受检异常(unCheckedException),有的运行时异常可以不做处理,比较普遍,所以可以暂不处理。
    • NullPointerException 空指针异常
    • ArithmeticException 数学运算异常
    • ArrayIndexOutOfBoundsException 数组下标越界异常
    • ClassCastException 类型转换异常
    • NumberFormatException 数字格式不正确异常
    • 等等
  • 编译时异常,受检异常(CheckedException),必须要在编译前处理的异常。
    • SQLException:操作数据库的异常
    • IOException:文件操作出现的异常
    • FileNotFoundException:文件未找到异常,一般用于IO流
    • ClassNotFoundException:类未找到异常
    • IllegalArgumentException:参数异常

25、什么是字符串常量池?

字符串常量池位于堆中,一般用于储存字符串常量。当创建字符串时,会先检查是否在字符串常量池中已经有这个字符串了。如果存在就用这个的引用,如果不存在就创建,这样可以大大提高字符串的使用效率。

26、String是不可变的吗?

是的因为String的底层用了final修饰。

/** The value is used for character storage. */
private final char value[];

27、如何将字符串反转?

通过StringBuilder和StringBuffer的reverse()方法。

public static void main(String[] args) {
    StringBuffer str = new StringBuffer("helloworld");
    StringBuffer reverse = str.reverse();
    System.out.println(reverse);
}

28、数组有没有 length()方法?String 有没有 length()方法?

数组没有length方法,只有length属性。

String有length方法

public static void main(String[] args) {
    String str = new String("abcdefg");
    int length = str.length();
    System.out.println(length);
    int[] arr = new int[]{1,2,3,4,5,6};
    System.out.println(arr.length);
}

29、String 类的常用方法都有那些?

String类的方法:

方法名描述
indexOf()返回指定字符的索引
charAt()返回指定索引处的字符
replace()字符串替换
trim()去除字符串两端空白
split()分割字符串,返回一个分割后的字符串数组
getBytes()返回字符串的 byte 类型数组
length()返回字符串长度
toLowerCase()将字符串转成小写字母
toUpperCase()将字符串转成大写字符
substring()截取字符串
equals()字符串比较

30、String和StringBuffer、StringBuilder的区别是什么?

String是不可变的字符串类型,创建的字符串是不可变的。

StringBuffer:StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,char[] value,这两种对象都是可变的。

而StringBuffer不是线程安全的,StringBuilder是线程安全的。用synchronized修饰了,所以StringBuffer的效率比StringBuilder的效率高。