JAVA基础

equals和==的区别:

​ 对于基本数据类型,int,double等,“==”号判断两者的数值是否相等,而对于字符串(引用数据类型),如“Hello!”对象,“==”号判断的是两者的指向字符串地址是否相同,如要判断两个字符串其中的每一个字符是否相同,可以用equals()方法。

​ 注意,如果字符串在创建时没有选择重建字符串,那么两个对象指向的字符串地址是一致的,但是如果修改其中一个对象的值,该对象指向的字符串地址会改变,另外一个对象仍旧指向原来的字符串地址没有改变,这是在底层的java逻辑设置中的(String)。但是一开始就是重建两个字符串则不存在这样的问题,就是说即使两个对象创建的字符串相同,这两个对象指向的字符串地址也不一致。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package practiceClass.a0512;

public class a01_test {
public static void main(String[] args) {
String A = new String("Sort");
String B = new String("Sort");
String C = "Sort";
String C_1 = "Sort";
System.out.println(A.equals(B)); // True
System.out.println(A.equals(C)); // True
System.out.println(B == C); // False
System.out.println(A == B); // False
System.out.println(C == C_1); // True
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class b01_test {
public static void main(String[] args) {
String A = new String("Sort");
String B = new String("Sort");
String C = "Sort";
String C_1 = "Sort";
C_1 = C_1 + "ing";
System.out.println(A.equals(B)); // True
System.out.println(A.equals(C)); // True
System.out.println(B == C); // False
System.out.println(A == B); // False
System.out.println(C == C_1); // False
System.out.println(C); // Sort
System.out.println(C_1); // Sorting
}
}

类型封装

iterger是int的对象类型封装,因为java是面向对象编程的。

重写和重载

方法的重写

Override

  1. 当父类的方法不能满足子类现在的需求时,需要进行方法的重写
  2. 格式是在重写后的方法上面加上 ‘@Override’ ,该标志是用来校验子类重写的方法格式是否是正确的,当然不加也可以,但最好加上
  3. 子类的重写方法权限最好用父类的保持一致,当然子类的权限可以大于等于父类

方法的重载

Overload

重载用于提供同一操作的不同实现,如下面都是函数相加,虽然变量数不同,却都可以用同一个函数名来表示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class b02_overload {
public static int sumTest(int a, int b) {
return a + b;
}
public static int sumTest(int a, int b, int c) {
return a + b + c;
}
public static int sumTest(int a, int b, int c, int d) {
return a + b + c + d;
}


public static void main(String[] args) {
System.out.println(sumTest(1, 2));
System.out.println(sumTest(1, 2, 3));
System.out.println(sumTest(1, 2, 3, 4));
}

}
1
2
3
3
6
10

背诵总结

Java中的重写和重载是实现多态的两种不同方式。

方法的重载是编译时多态,指的是在同一个类中,可以存在有相同名称的多个方法,它们的参数列表不同(参数的类型、个数、顺序),也可以有不同的返回类型和访问修饰符。

方法的重写是运行时多态,指的是在子类中重新定义父类中已经定义的方法,子类中的方法名、参数列表和返回类型都必须相同。重写的方法的访问级别不能低于被重写的父类方法,虚拟机在运行时根据对象的实际类型来确定调用哪个方法。

​ 总结来说,重载关注的是方法的多样性,允许同一个类中存在多个同名方法;而重写关注的是方法的一致性,允许子类提供特定于其自己的行为实现。

单与运算符&和双与运算符&&的区别

在 Java 中,&&& 都是逻辑运算符,但它们的作用和使用场景有所不同:

  1. &(按位与运算符):

    • 用途& 是按位与运算符,通常用于整数类型(如intlong)的按位操作。它逐位对两个操作数进行“与”运算。只有对应的位都是 1 时,结果才是 1,否则是 0。
    • 逻辑操作& 也可以用于布尔值(boolean)的逻辑运算,但它没有短路行为。
    • 短路行为& 不具有短路行为,即它总是会对两个操作数都进行求值。

    示例

    1
    2
    3
    int a = 5;   // 0101
    int b = 3; // 0011
    int c = a & b; // 0001, 结果是 1

    对于布尔类型:

    1
    2
    3
    boolean x = true;
    boolean y = false;
    boolean result = x & y; // 结果是 false

    无论 xy 的值如何,& 运算符都会对两个布尔值都进行求值。

  2. &&(逻辑与运算符):

    • 用途&& 是逻辑与运算符,专门用于布尔值的逻辑运算。它在两边的操作数都是布尔值时返回一个布尔结果。
    • 短路行为&& 具有短路行为。如果第一个操作数为 false,它就不会再计算第二个操作数,因为 false && 后面的任何值都不会影响结果。这种特性可以提高效率,避免不必要的计算。

    示例

    1
    2
    3
    boolean x = true;
    boolean y = false;
    boolean result = x && y; // 结果是 false

    如果用于短路:

    1
    2
    3
    boolean x = false;
    boolean y = someMethod(); // someMethod() 可能会抛出异常
    boolean result = x && y; // 由于 x 为 false,y 不会被求值,someMethod() 不会被调用,也就不会抛出异常

总结:

  • & 是按位与运算符,通常用于整数类型的按位运算,或布尔类型的逻辑运算,但没有短路行为。
  • && 是逻辑与运算符,专门用于布尔值的逻辑运算,且具有短路行为。

因此,&& 在布尔逻辑中更常用,尤其在控制流语句(如if语句)中,它能有效提高程序效率和防止潜在错误。

形参和实参

形参是定义通用方法时输入的形式参数,如Person p

而实参是在实际调用这个方法时输入的实际参数,如Student s、Teacher t

String,StringBuffer和StringBuilder

特性 String StringBuffer StringBuilder
是否可变 不可变 可变 可变
变量是否跨线程 不跨
使用场景 字符串内容少量修改 多线程环境下同步修改 单线程环境下修改

​ 因此,在实际开发中

  1. 如果字符串很少修改,直接使用不可变的String
  2. 如果在多线程环境下频繁操作字符串,可以选择StringBuffer
  3. 如果是单线程,用StringBuilder

变量可以跨线程我们叫线程不安全

​ 当多个线程同时访问和修改同一个变量时,如果没有适当的同步机制来保证线程之间的顺序和互斥访问,这个变量就被认为是线程不安全的。这种情况会导致竞争条件(race condition),即多个线程在没有协调的情况下同时修改变量的值,最终导致不可预测的结果。

抽象类和接口的区别

抽象类

​ 抽象类本质是一个类,它是在原有类的基础上,增加了抽象的能力,即可以定义抽象方法。正是因为它可以拥有抽象方法,所以即便有构造器(无参有参构造),也不能直接创建对象。

接口

​ 接口则是完全抽象(所有的方法在接口中都没有实现)。(JDK8之后,接口中可以包含默认方法和静态方法)

区别

  1. 一个类只能继承一个抽象类;可以实现多个接口

  2. 抽象类中方法和字段可以是任何访问修饰符;接口中的方法默认都是public abstract,字段默认都是public static final

  3. 抽象类用于定义一个类的公共行为和状态,表示 是什么;接口用于定义一组行为规范,表示 *能做什么

java常见的异常类有哪些

区别

编译时异常:通常是由外部因素引发的异常(如文件I/O操作、数据库连接失败等) ,开发者无法完全预知这些问题,因此编译器强制要求进行处理。

运行时异常:一般是由开发者的编程错误或逻辑漏洞引发的,属于程序内部的问题,开发者理论上可以预知,可以在调试阶段发现处理。

处理方式

编译时异常:使用try-catch或者throws关键字声明抛出。

运行时异常:通常选择使用try-catch捕获处理或程序终止时由JVM抛出

常见的编译时异常:

SQLException:数据库访问出错。

FileNotFoundException :文件未找到。

ClassNotFoundException:无法找到指定类。

InterruptedException :线程在阻塞状态被打断。

常见的运行时异常:

ArithmeticException:数学运算错误,例如除以零。

ClassCastException:强制类型转换失败。

ArrayIndexOutofBoundsException:数组索引越界。

try-catch-finally

不带 return 的执行顺序

异常处理中,try、catch 、finally 的执行顺序:

  • 如果 try 中没有异常,执行顺序为:try —> finally
  • 如果 try 中有异常,执行顺序为:try —> catch —> finally

带 return 的执行顺序

  • finally 中的代码总会执行
  • 当 try、catch 中有 return 时,也会执行 finally。
  • finally 中有 return 时,会直接在 finally 中退出,导致 try、catch 中的 return 失效

Java面向对象三大特性

Java面向对象编程的三大特性是封装、继承和多态:

  1. 封装:封装是将对象的属性(成员变量)和行为(成员方法)结合在一起,并隐藏内部的实现细节,只暴露出一个可以被外界访问的接口。
  2. 继承:允许一个类(子类)继承另一个类(父类)的属性和方法的机制。子类可以重用或者重写父类的方法,一个类只能直接继承一个父类。
  3. 多态:多态是指允许不同类的对象对同一消息做出响应,但具体的行为会根据对象的实际类型而有所不同。这通常通过方法重载和重写实现。(背下面)

Java多态

  1. 多态是指:创建对象时,使用父类型作为参数,接受所有的子类对象,使用该对象的方法时,其方法行为总是表现出子类方法的行为特征,而不是父类方法的行为特征,这就可能出现:相同类型的对象、调用同一个方法时呈现出多种不同的行为特征。

优势和劣势

优势
  1. 创建对象时,使用父类型作为参数,可以接受所有的子类对象,子类对象可以实现解耦合,便于扩展和维护。
1
2
Person p = new Student(); // 当业务逻辑发生变化时,只需要将这里的Student改变即可
p.work();
劣势

​ 多态的父类方法定义往往不能面面俱到,而多态方法的定义往往是编译看左边,运行看右面。因此,我们如果想调用子类中的特有方法,而这种方法在多态中没有的话(不是用Override重写的方法),编译就会报错,为了解决这个问题,我们会对变量对象进行强转,将之前声明的父类对象强转为子类对象。

final关键字有什么作用

final 就是不可变的意思,可以修饰变量、方法和类。

  1. 修饰变量:
    1. final 修饰 基本数据类型的变量,其数值一旦在初始化之后便不能更改, 称为常量;
    2. final 修饰 引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。虽然不能再指向其他对象,但是它指向的对象的内容是可变的
  2. 修饰方法: final修饰方法是明确禁止该方法在子类中被覆盖
  3. 修饰类: final 修饰的类不可被继承,是最终类。