Java面对对象编程复习(附带面试题)

目录

一.了解java

二.程序的基本概念

三.程序逻辑的控制

四.方法

五.类与对象

六.数组

七 .String类

八.继承

九.抽象类与接口

十.类结构扩展

十一.异常的捕捉与处理

十二.内部类


一.了解java

1.java实现一致性靠的是JVM,JVM本质是一台虚拟机,只要在不的操作系统上植入不不同版本的jvm,那么 Java 程序就可以在各个平台上移植,做到“一次编写,处处运行”

2.Java 中程序的执行步骤如下
使用javac命令将一个*java 文件编译成*class 文件
使用 java 命令可以执行一个*.class 文件。

3.每次使用java 命令执行一个 class 的时候,都会启动JVM 进程,JVM 通过 CLASSPATH 给出的
路径加载所需要的类文件,可以通过 SET CLASSPATH 设置类的加载路径。

4.Java 程序主要分为两种: Java Application 和 Java Applet 程序,Java Applet 主要是在网页中嵌入的Java 程序,基本上已经不再使用了, 而 Application 是指有 main 方法的程序

5.JDK1.9 之后的开发包中提供有 JShell 交式工具,利用此工具可以直接执行程序代码,从而避免主方法执行的限制。但此类操作只适合于简单的编程,在实际开发之中还是建议使用标准的程序结构开发程序。

*面试题  JDK,JRE,JVM三者之间的关系

 1.JDK(java development Kit)是针对Java开发员的产品,是Java的核心,包括Java的运行环境,JRE,JAVA工具和Java基础类库。

2.JRE(Java runtime environment)是运行Java程序所必须的环境集合,包含jvm标准实现以及Java核心类库

3.JVM(java virtual machine)是整个Java跨平台的最核心部分,能够运行java语言编写的软件程序

*面试题 1、JDK 和 JRE 有什么区别?

JDK(Java Development Kit),Java开发工具包

JRE(Java Runtime Environment),Java运行环境

JDK中包含JRE,JDK中有一个名为jre的目录,里面包含两个文件夹bin和lib,bin就是JVM,lib就是JVM工作所需要的类库。


二.程序的基本概念

1.程序开发利用注释可以提升程序源代码的可阅读性,在 Java 中提供有 3 类注释,单行注释、多行注释和文档注释。

2.标识符是程序单元定义的唯一标记,可以定义类、方法、变量,Java 中标识符组成原则: 字母数字、_、$所组成,其中不能以数字开头,不能使用 Java 的关键字,并且也可以使用中文进行标识符定义。

3.Java 的数据类型可分为下列两种:基本数据类型引用数据类型。其中,基本数据类型可以直接进行内容处理,而引用数据类型需要进行内存空间的分配后才可以使用

4.Unicode 为每个字符制定了一个唯一的数值,因此在任何语言、平台和程序上都可以安心使用

5.布尔 (boolean)类型的变量只有 true (真)和 false (假) 两个值。
6.数据类型的转换可分为“自动类型转换”与“强制类型转换”,在进行强制类型转换时需要注意数据溢出。
7.算术运算符的成员有加法运算符、减法运算符、乘法运算符、除法运算符和余数运算符

8.递增与递减运算符有着相当大的便利性,善用它们可提高程序的简洁程度。
9.任何运算符都有执行顺序,在开发中建议利用括号来修改运算符的优先级.
10.逻辑“与”和逻辑“或”操作分别提供有“普通与、或”与“短路与、或”两类,开发中建议使用“短路与、或”操作提升程序的执行性能。

 *面试题String 属于基础的数据类型吗?

不属于。

八种基本数据类型:byte、short、char、int、long、double、float、boolean。

*面试题byte类型127+1等于多少

byte的范围是 -128~127。

字节长度为8位,最左边的是符号位,而127的二进制为01111111,所以执行+1操作时,01111111变为10000000。

大家知道,计算机中存储负数,存的是补码的兴衰。左边第一位为符号位。

那么负数的补码转换成十进制如下:

一个数如果为正,则它的原码、反码、补码相同;一个正数的补码,将其转化为十进制,可以直接转换。

已知一个负数的补码,将其转换为十进制数,步骤如下:

    先对各位取反;
    将其转换为十进制数;
    加上负号,再减去1;

例如10000000,最高位是1,是负数,①对各位取反得01111111,转换为十进制就是127,加上负号得-127,再减去1得-128;


三.程序逻辑的控制

1.f语句可依据判断的结果来决定程序的流程。
2,选择结构包含 if、if ..elseswitch 语句,语句中加上了选择的结构之后,根据选择的不同,程序的运行会有不同的方向与结果。
3.需要重复执行某项功能时,最好使用循环结构。可以选择使用Java 所提供的 for  whiledo...while循环来完成。
4.break 语句可以强制程序逃离循环。当程序运行到 break 语句时,即会离开循环,执行循环外的语句,如果 break 语句出现在嵌套循环中的内层循环,则 break 语只会逃离当前层循环。
5,continue 语句可以强制程序跳到循环的起始处,当程序运行到 continue 语句时,即会停止运行剩余的循环主体,而回到循环的开始处继续运行。

public class ContinueExample {
    public static void main(String[] args) {
        for (int i = 1; i <= 5; i++) {
            if (i == 3) {
                // 当 i 等于 3 时,跳过当前迭代
                continue;
            }
            System.out.println("Number: " + i);
        }
    }
}


四.方法

1.方法是一段可重复调用的代码段,因为方法可以由主方法直接调用,所以要加入 public    static 关键字修饰。

2.方法的重载:方法名称相同,参数的类型或个数不同,则此方法被称为重载。

//重载
public class MathUtils {
    public int add(int a, int b) {
        return a + b;
    }

    public double add(double a, double b) {
        return a + b;
    }
    
    public int add(int a, int b, int c) {
        return a + b + c;
    }

    public static void main(String[] args) {
        MathUtils math = new MathUtils();
        
        int sum1 = math.add(2, 3);
        System.out.println("Sum of integers: " + sum1);
        
        double sum2 = math.add(2.5, 3.7);
        System.out.println("Sum of doubles: " + sum2);
        
        int sum3 = math.add(2, 3, 4);
        System.out.println("Sum of three integers: " + sum3);
    }
}

3.方法递归调用指的是本方法的自身重复执行,在使用递归调用时一定要设置好方法的结束条件否则就会出现内存溢出问题,造成程序中断执行。

*面试题 在 Java 中,为什么不允许从静态方法中访问非静态变量?

  • 静态变量属于类本身,在类加载的时候就会分配内存,可以通过类名直接访问;
  • 非静态变量属于类的对象,只有在类的对象产生时,才会分配内存,通过类的实例去访问;
  • 静态方法也属于类本身,但是此时没有类的实例,内存中没有非静态变量,所以无法调用

五.类与对象

1.面向对象程序设计是现在主流的程序设计方法,它有三大主要特性:封装性、继承性、多态性。
2.类与对象的关系:类是对象的模板,对象是类的实例,类只能通过对象才可以使用。
3.类的组成:成员属性(Field)和方法(Method)。
4.对象的实例化格式:类名称 对象名称 = new 类名称(),关键字new用于为对象分配内存空间。
5.如果一个对象没有被实例化而直接使用,则会出现空指针异常(NullPointerException)。
6.类属于引用数据类型,在引用传递时,传递的只是堆内存的地址(多个栈内存可以指向同一块堆内存).

7.类的封装性:通过private关键字修饰属性,被封装的属性不能被外部直接访问,只能通过setter和getter方法访问。所有属性都应该进行封装。
8.构造方法可以用于初始化类的属性,构造方法与类名称相同,并且没有返回值类型声明。如果在类中没有明确定义构造方法,系统会自动生成一个无参的空构造方法。一个类中可以有多个构造方法,称为构造方法的重载,但每个类必须至少有一个构造方法
9.在Java中使用this关键字表示当前对象,通过"this.属性"调用本类中的属性,通过"this.方法()"调用本类中的其他方法。还可以使用this()调用本类中的构造方法,但要放在构造方法的首行。

public class Person {
    private String name;
    private int age;

    // 构造方法1:接收name和age作为参数进行初始化
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 构造方法2:接收name参数进行初始化,将age设置为默认值0
    public Person(String name) {
        this(name, 0); // 调用构造方法1,传递name和默认值0
    }
    
    // 其他方法
    public void introduce() {
        System.out.println("My name is " + this.name + ", and I am " + this.age + " years old.");
    }
}

例如使用以下代码创建Person对象:

Person person1 = new Person("Alice", 25);
person1.introduce(); // 输出: My name is Alice, and I am 25 years old.

Person person2 = new Person("Bob");
person2.introduce(); // 输出: My name is Bob, and I am 0 years old.


10.使用static关键字声明的属性和方法可以直接通过类名称调用,static属性是所有对象共享的,所有对象都可以对其进行操作。

*面试题 Java具有哪三大特性:

三大特性:封装性,继承性,多态性

  1. 封装性:指的是将类的信息隐藏在内部,外部程序不允许直接访问,而是通过类的方法对隐藏信息的操作和访问
  2. 继承性: 继承是类鱼类之间的一种关系,比较像集合中的从属关系,子类可以获取到父类的属性和方法,在Java中是单继承的,一个子类只有一个父类
  3. 多态性:Java语言允许某个类型的引用变量引用子类的实例,而且可以对这个引用变量进行类型转换

 *面试题: final 在 java 中有什么作用?

用来修饰一个引用

  1.  如果引用为基本数据类型,则该引用为常量,该值无法修改;
  2.  如果引用为引用数据类型,比如对象、数组,则该对象、数组本身可以修改,但指向该对象或数组的地址的引用不能修改。
  3.  如果引用时类的成员变量,则必须当场赋值,否则编译会报错。

六.数组

1.数组是一组相关数据变量的线性集合,利用数组可以方便地实现一组变量的关联,数组的缺点在于长度不可改变。
2.数组在访问时需要通过“数组名称[索引”的形式访问,索引范围为 0~数组长度-1,如果超过数组索引访问范围则会出现“java.lang.ArrayIndexOutOfBoundsException”异常。

3.数组长度可以使用“数组名称.length”的形式动态获取
4.数组采用动态初始化时,数组中每个元素的内容都是其对应数据类型的默认值。

数组的静态初始化与动态初始化:

int[] numbers = {1, 2, 3, 4, 5}; // 静态初始化
String[] names;
names = new String[]{"Alice", "Bob", "Charlie"}; // 静态初始化

int[] scores = new int[5]; // 动态初始化,长度为5,默认值为0
String[] cities = new String[3]; // 动态初始化,长度为3,默认值为null

总结:

  • 静态初始化是在创建数组时直接为数组元素赋初值,可在声明数组时进行。
  • 动态初始化是先创建数组对象,再为数组元素分配内存并设定初值,适用于需要根据运行时需求确定数组长度的情况。

5.数组属于引用数据类型,在使用前需要通过关键字 new 为其开辟相应的堆内存空间,如果使用
了未开辟堆内存空间的数组则会出现“java.lang.NullPointerException”异常。
6.JDK 为了方便数组操作提供有 System.arraycopy0与 java.util.Arrayssort0两个方法实现数组复制与数组排序。

int[] sourceArray = {1, 2, 3, 4, 5};
int[] targetArray = new int[5];

System.arraycopy(sourceArray, 0, targetArray, 0, sourceArray.length);

// 输出目标数组
for (int i = 0; i < targetArray.length; i++) {
    System.out.println(targetArray[i]);
}

int[] array = {5, 3, 1, 4, 2};

Arrays.sort(array);

// 输出排序后的数组
for (int i = 0; i < array.length; i++) {
    System.out.println(array[i]);
}


7.JDK 1.5 之后开始追加了可变参数,这样使得方法可以任意接收多个参数,接收的可变参数使用数组形式处理。

public class VarargsExample {
    public static void printValues(String... values) { // 使用可变参数
        for (String value : values) {
            System.out.println(value);
        }
    }

    public static void main(String[] args) {
        printValues("Hello", "World"); // 可以传递任意数量的参数
        printValues("Java", "is", "awesome");
        printValues(); // 也可以不传递任何参数
    }
}


8.对象数组可以实现一组对象的管理,在开发中可以描述多个实例。

与枚举的区别:

  • 对象数组是一种通用的数据结构,可用于存储多个对象引用,使其更灵活地管理和操作这些对象。
  • 枚举是一种特殊的数据类型,用于定义一组有限的常量,并提供更加可读性和类型安全性的常量值。

9.简单 Java 类可以实现数据表结构的映射转换,通过面向对象的关联形式描述数据表存储结构。


七 .String类(重点内容)

1.String 类在 Java 中较为特殊,String 可以通过直接赋值或构造方法进行实例化。前者只产生一个实例化对象,而且此实例化对象可以重用;而后者将产生两个实例化对象,其中一个是垃圾空间。

重用与重载的区别

  1. 重用(Reuse):

    • 重用是指使用已有的代码、组件或功能来实现新的功能或解决新的问题,以减少开发时间和工作量。
    • 在面向对象编程中,重用通常通过继承和组合来实现。
    • 继承允许子类继承父类的属性和方法,在子类中可以直接使用继承得到的属性和方法,以实现代码的重用。
    • 组合是将多个类组合在一起以实现特定功能,通过将一个类的对象作为另一个类的成员变量,以实现代码的复用。
  2. 重载(Overload):

    • 重载是指在同一个类中定义多个同名但参数列表不同的方法,以实现方法的多态性。
    • 重载方法具有相同的名称但不同的参数数量、类型或顺序,编译器根据方法调用时提供的参数来选择匹配的方法进行调用。
    • 重载方法可以根据不同的需求和情况,提供不同的方法实现,但它们具有相似的功能。

2.JVM 提供有两类 String 常量池:静态常量池、运行时常量池。对于静态常量池,需在编译的时
候进行字符串处理,运行时常量池是在程序执行中动态地实例化字符串对象。

3.在 String 中比较内容时使用 equals()方法,而“==”比较的只是两个字符串的地址值。

4.字符串的内容一旦声明则不可改变。而字符串变量的修改是通过引用地址的变更而实现的,但是会产生垃圾空间。
5.在使用 String类的 split0方法时需要考虑正则表达式的影响,需要使用“\\”进行转义处理

String str = "Hello. World. How. Are. You?";
String[] parts = str.split("\\."); // 使用两个反斜杠进行转义处理

for (String part : parts) {
    System.out.println(part);
}

6.如果要对字符串编码进行转换可以用getBytes()方法实现

面试题 :在 Java 中,什么时候用重载,什么时候用重写?

(1)重载是多态的集中体现,在类中,要以统一的方式处理不同类型数据的时候,可以用重载。

(2)重写的使用是建立在继承关系上的,子类在继承父类的基础上,增加新的功能,可以用重写。

(3)简单总结:

重载是多样性,重写是增强剂;
目的是提高程序的多样性和健壮性,以适配不同场景使用时,使用重载进行扩展;
目的是在不修改原方法及源代码的基础上对方法进行扩展或增强时,使用重写;

 面试题 :== 和 equals 的区别是什么?

  1. 对于基本类型,==比较的是值;
  2. 对于引用类型,==比较的是地址;
  3. equals不能用于基本类型的比较;
  4. 如果没有重写equals,equals就相当于==;
  5. 如果重写了equals方法,equals比较的是对象的内容;

 面试题 :String 类的常用方法都有那些?

(1)常见String类的获取功能

length:获取字符串长度;
charAt(int index):获取指定索引位置的字符;
indexOf(int ch):返回指定字符在此字符串中第一次出现处的索引;
substring(int start):从指定位置开始截取字符串,默认到末尾;
substring(int start,int end):从指定位置开始到指定位置结束截取字符串;

(2)常见String类的判断功能

equals(Object obj): 比较字符串的内容是否相同,区分大小写;
contains(String str): 判断字符串中是否包含传递进来的字符串;
startsWith(String str): 判断字符串是否以传递进来的字符串开头;
endsWith(String str): 判断字符串是否以传递进来的字符串结尾;
isEmpty(): 判断字符串的内容是否为空串"";

(3)常见String类的转换功能

byte[] getBytes(): 把字符串转换为字节数组;
char[] toCharArray(): 把字符串转换为字符数组;
String valueOf(char[] chs): 把字符数组转成字符串。valueOf可以将任意类型转为字符串;
toLowerCase(): 把字符串转成小写;
toUpperCase(): 把字符串转成大写;
concat(String str): 把字符串拼接;

(4)常见String类的其他常用功能

replace(char old,char new) 将指定字符进行互换
replace(String old,String new) 将指定字符串进行互换
trim() 去除两端空格
int compareTo(String str) 会对照ASCII 码表 从第一个字母进行减法运算 返回的就是这个减法的结果,如果前面几个字母一样会根据两个字符串的长度进行减法运算返回的就是这个减法的结果,如果连个字符串一摸一样 返回的就是0。

 面试题 :new String("a") + new String("b") 会创建几个对象?

对象1:new StringBuilder()

对象2:new String("a")

对象3:常量池中的"a"

对象4:new String("b")

对象5:常量池中的"b"

深入剖析:StringBuilder中的toString():

对象6:new String("ab")

强调一下,toString()的调用,在字符串常量池中,没有生成"ab"


八.继承

        1.继承可以扩充已有类的功能。通过 extends 关键字实现,可将父类的成员 (包含数据成员与方法)继承到子类。

        2. Java 在执行子类的构造方法之前,会先调用父类中无参的构造,其目的是为了对继承自父类的成员做初始化的操作,当父类实例构造完毕后再调用子类构造。

        3.父类有多个构造方法时,如要调用特定的构造方法,则可在子类的构造方法中,通过 super())这个关键字来完成。

4.在同一类中,使用"this"关键字调用其他构造函数,而"super()"关键字则用于从子类的构造函数中调用父类的构造函数。

5.当使用"this"访问属性或方法时,它首先在当前类中查找。如果找不到,则会在父类中继续查找。而使用"super()"则直接在父类中查找所需的属性或方法。

6."this()"与"super()"的相似之处是,当构造函数重载时,两者都可以根据提供的参数类型和数量来调用相应的构造函数。同时,"this()"和"super()"必须作为构造函数体内的第一行代码写入。这也是为什么"this()"和"super()"不能同时存在于同一个构造函数中的原因。

7."重载"是指在同一个类中定义相同名称但参数个数或类型不同的方法。Java可以根据参数的数量或类型调用相应的方法。

8."覆盖"是指在子类中定义与父类具有相同名称、参数个数和类型的方法,以覆盖父类中的方法。

9.如果父类的方法不希望被子类覆盖,可以在方法前加上"final"关键字,这样就防止了方法被覆盖。

10."final"关键字的另一个用途是将变量声明为常量,在变量声明之前添加"final"关键字后,该变量在程序中无法被修改。使用"public static final"可以声明全局常量。

11.对象的多态性主要分为自动向上转型和强制向下转型。为了避免在进行向下转型时出现ClassCastException异常,可以使用"instanceof"关键字在转型之前检查实例的类型。

向上转型与向下转型:

向上转型(Upcasting)向下转型(Downcasting)
定义将子类实例赋值给其父类类型的引用变量。将父类实例赋值给其子类类型的引用变量。
语法父类类型 引用变量 = new 子类();子类类型 引用变量 = (子类类型) 父类引用变量;
隐式或显式类型转换隐式的(无需显式类型转换)。显式的(需要使用括号进行显式类型转换)。
用途允许通过父类引用调用子类对象中从父类继承的属性与方法。允许通过子类引用调用从父类继承的属性与方法以外,还可以使用子类特有的属性与方法。
异常不会引发ClassCastException异常。如果待转换的对象不是期望的子类类型,则可能引发ClassCastException异常。

12.所有的类都继承自Object类,所有引用数据类型都可以向上转型为Object类。通过使用Object,方法可以统一接收参数或返回数据类型。


九.抽象类与接口

  1. Java 可以创建抽象类,抽象类相当于一个模板,用作其他类的父类。抽象类的目的是提供一个格式,供其他类根据需要进行修改和创建新类。
  2. 抽象类的方法可以分为两种:普通方法和抽象方法。抽象方法是以 abstract 关键字开头且没有方法体的方法,它必须在派生类(子类)中进行强制性的重写。
  3. 抽象类不能直接通过关键字 "new" 实例化对象,而是需要使用子类对象的向上转型来实例化。
  4. 接口是方法和全局常量的集合,子类必须实现接口中定义的所有方法。一个接口可以继承多个接口,一个类可以通过 "implements" 关键字实现多个接口。
  5. 从 JDK 1.8 版本开始,接口中允许定义默认方法和静态方法。
  6. Java 不支持类的多重继承,但支持实现多个接口,实现了接口相当于实现了多继承的概念。

接口与抽象类区别:

抽象类接口
可以包含抽象方法和非抽象方法只能包含抽象方法和默认方法
子类可以使用extends关键字继承抽象类子类可以使用implements关键字实现接口
可以有构造方法不允许有构造方法
可以有实例变量只能有常量(静态和非静态)
支持单继承支持多继承(实现多个接口)
可以拥有访问修饰符所有方法默认为public修饰符
用于代码重用和继承的具体实现用于实现多态性和约束行为
  1. 接口可以通过扩展来派生出新的接口,原始接口称为基本接口或父接口,派生接口称为派生接口或子接口。派生接口既保留了父接口的成员,也可以添加新的成员以满足实际需求。
  2. 使用泛型可以避免使用 Object 接收参数时出现的 ClassCastException 问题。
public class Container<T> {
    private T data;

    public Container(T data) {
        this.data = data;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}
Container<String> stringContainer = new Container<>("Hello");
System.out.println(stringContainer.getData()); // 输出:Hello

Container<Integer> intContainer = new Container<>(123);
System.out.println(intContainer.getData()); // 输出:123

  1. 在引用泛型对象时,应该使用通配符 "?"(或相关上限、下限设置)来描述泛型参数。

面试题: 普通类和抽象类有哪些区别?

抽象类不能被实例化;
抽象类可以有抽象方法,只需申明,无须实现;
有抽象方法的类一定是抽象类;
抽象类的子类必须实现抽象类中的所有抽象方法,否则子类仍然是抽象类;
抽象方法不能声明为静态、不能被static、final修饰。

 面试题:接口和抽象类有什么区别?

(1)接口

接口使用interface修饰;
接口不能实例化;
类可以实现多个接口;

①java8之前,接口中的方法都是抽象方法,省略了public abstract。②java8之后;接口中可以定义静态方法,静态方法必须有方法体,普通方法没有方法体,需要被实现;

(2)抽象类

抽象类使用abstract修饰;
抽象类不能被实例化;
抽象类只能单继承;
抽象类中可以包含抽象方法和非抽象方法,非抽象方法需要有方法体;
如果一个类继承了抽象类,①如果实现了所有的抽象方法,子类可以不是抽象类;②如果没有实现所有的抽象方法,子类仍然是抽象类。


十.类结构扩展

1.Java 中使用包进行各个功能类的结构划分,也可以解决在多人开发时所产生的类名称重复的问题。
2.在Java 中使用 package 关键字将一个类放入一个包中,包的本质就是一个目录,在开发中往往需要依据自身的开发环境定义父包名称和子包名称,在标准开发中所有的类都必须放在一个包内
3.在 Java 中使用 import 语句,可以导入一个已有的包。
4.如果在一个程序中导入了不同包的同名类,在使用时一定要明确指出包的名称,即“包.类名称”

5.Java 中的访问控制权限分为4 种: private、default、protected、public。

以下是四种权限的区别:

修饰符同一类同一包内子类同一包内其他类不同包子类不同包其他类
private
default
protected
public

6.使用jar 命令可以将一个包打成一个jar 文件,供用户使用。

7.单例设计模式与多例设计模式都必须要求构造方法私有化,同时需要在类的内部提供好实例化对象,利用引用传递交给外部类进行使用。

8.JDK 1.5 之后提供的枚举类型可以简化多例设计模式的定义,同时可以提供更加丰富的类结构定义。
9,使用 enum 关键字定义的举将默认继承 Enum 父类,在 Enum 类中的构造方法使用 protected 权限定义,并且要接收枚举的名称和序号(根据枚举的对象定义顺序自动生成)

public enum Weekday {
    MONDAY(1),
    TUESDAY(2),
    WEDNESDAY(3),
    THURSDAY(4),
    FRIDAY(5);

    private int dayNumber;

    protected Weekday(int dayNumber) {
        this.dayNumber = dayNumber;
    }

    public int getDayNumber() {
        return dayNumber;
    }
}

Weekday monday = Weekday.MONDAY;
System.out.println(monday.getDayNumber()); // 输出:1


十一.异常的捕捉与处理

  1. 异常是导致程序中断运行的一种指令流,当异常发生时,如果没有进行良好的处理,则程序将会中断执行
  2. 异常处理可以使用 try...catch 结构进行处理,也可以使用 try...catch...finally 结构进行处理。在 try 语句中捕捉异常,之后在 catch 中处理异常,finally 作为异常的统一出口,不管是否发生异常都要执行此段代码。
  3. 异常的最大父类是 Throwable,其分为两个子类:Exception 和 Error。Exception 表示程序处理异常,而 Error 表示 JVM 错误,一般不由程序开发人员处理。
  4. 发生异常之后,JVM 会自动产生一个异常类的实例化对象,并匹配相应的 catch 语句中的异常类型,也可以利用对象的向上转型关系,直接捕获 Exception
  5. throws 用在方法声明处,表示本方法不处理异常
  6. throw 表示在方法中手动抛出一个异常。

throws与throw区别:

throwsthrow
用途在方法签名中声明可能抛出的异常主动抛出一个特定的异常
语法在方法声明后的括号内使用在方法体内使用
异常处理将异常传递给调用者进行处理立即抛出异常,终止当前方法的执行
多异常可以同时声明多个异常只能抛出一个异常
  1. 自定义异常类的时候,只需继承 Exception 类或 RuntimeException 类即可。
// 自定义异常类
public class InvalidInputException extends Exception {
    public InvalidInputException(String message) {
        super(message);
    }
}
public class Example {
    public static void main(String[] args) {
        try {
            validateInput("abc");
        } catch (InvalidInputException e) {
            System.out.println("发生异常:" + e.getMessage());
        }
    }

    public static void validateInput(String input) throws InvalidInputException {
        if (input.length() < 5) {
            throw new InvalidInputException("输入长度不能小于5");
        }
    }
}
  1. 断言 (assert) 是 JDK 1.4 之后提供的新功能,可以用来检测程序的执行结果,但开发中并不提倡使用断言进行检测。

面试题: throw 和 throws 的区别?

(1)throw

作用在方法内,表示抛出具体异常,由方法体内的语句处理;
一定抛出了异常;

(2)throws

作用在方法的声明上,表示抛出异常,由调用者来进行异常处理;
可能出现异常,不一定会发生异常;

 面试题:final、finally、finalize 有什么区别?

final可以修饰类,变量,方法,修饰的类不能被继承,修饰的变量不能重新赋值,修饰的方法不能被重写

finally用于抛异常,finally代码块内语句无论是否发生异常,都会在执行finally,常用于一些流的关闭。

finalize方法用于垃圾回收。

一般情况下不需要我们实现finalize,当对象被回收的时候需要释放一些资源,比如socket链接,在对象初始化时创建,整个生命周期内有效,那么需要实现finalize方法,关闭这个链接。

但是当调用finalize方法后,并不意味着gc会立即回收该对象,所以有可能真正调用的时候,对象又不需要回收了,然后到了真正要回收的时候,因为之前调用过一次,这次又不会调用了,产生问题。所以,不推荐使用finalize方法。

  面试题:try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?

 面试题:常见的异常类有哪些?

  • NullPointerException:空指针异常;
  • SQLException:数据库相关的异常;
  • IndexOutOfBoundsException:数组下角标越界异常;
  • FileNotFoundException:打开文件失败时抛出;
  • IOException:当发生某种IO异常时抛出;
  • ClassCastException:当试图将对象强制转换为不是实例的子类时,抛出此异常;
  • NoSuchMethodException:无法找到某一方法时,抛出;
  • ArrayStoreException:试图将错误类型的对象存储到一个对象数组时抛出的异常;
  • NumberFormatException:当试图将字符串转换成数字时,失败了,抛出;
  • IllegalArgumentException 抛出的异常表明向方法传递了一个不合法或不正确的参数。
  • ArithmeticException当出现异常的运算条件时,抛出此异常。例如,一个整数“除以零”时,抛出此类的一个实例。

十二.内部类

  1. 内部类的最大作用在于可以与外部类直接进行私有属性的相互访问,避免对象引用所带来的麻烦。
  2. 使用 static 关键字定义的内部类表示外部类,可以在没有外部类实例化对象的情况下使用,同时只能访问外部类中的 static 结构定义。
  3. 匿名内部类主要应用于抽象类和接口上的扩展,利用匿名内部类可以有效地减少子类定义的数量。
  4. Lambda 是函数式编程的一种形式,是在匿名内部类的基础上发展而来的。Lambda 表达式使用的前提是该接口只允许有一个抽象方法,或者使用 "@FunctionalInterface" 注解定义。
List<String> fruits = Arrays.asList("apple", "banana", "orange", "grape", "watermelon");

// 使用 Lambda 表达式筛选名字长度大于5的水果
List<String> filteredFruits = fruits.stream()
                                   .filter(fruit -> fruit.length() > 5)
                                   .collect(Collectors.toList());

// 输出筛选后的水果列表
filteredFruits.forEach(System.out::println);

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

numbers.forEach(n -> {
    int square = n * n;
    System.out.println(square);
});

  1. 方法引用与对象引用类似,可以为方法进行别名定义。
  2. JDK 中提供了四个内建函数式接口:Function、Consumer、Supplier、Predicate。
作用示例
Function接收一个参数,并返回结果。常用于对输入进行转换、映射或组合操作。Function<Integer, String> convert = num -> String.valueOf(num);<br>String result = convert.apply(123); // 结果为 "123"
Consumer接收一个参数,对其执行某些操作,无返回值。常用于对给定的对象进行消费。Consumer<String> printer = str -> System.out.println(str);<br>printer.accept("Hello"); // 输出 "Hello"
Supplier不接收任何参数,提供一个结果。常用于生成或返回数据。Supplier<Double> randomNumber = () -> Math.random();<br>double num = randomNumber.get(); // 返回一个随机数
Predicate接收一个参数,返回一个布尔值。常用于对输入进行条件判断。Predicate<Integer> isEven = num -> num % 2 == 0;<br>boolean result = isEven.test(4); // 结果为 true
  1. 链表是一种线性的数据结构,所有的数据按照存储的先后关系进行保存。链表的实现核心是节点(Node)类的设计以及引用关系的配置。在实际开发中,优秀的链表设计不仅具有较高的查找性能,还适合多线程并发操作。本章介绍的链表只是对链表基本原理的分析,实际开发中会使用 JDK 提供的类集来代替自己实现链表。
  2. 宠物商店程序中的模式是一种常用的设计模式,通过接口作为标准实现应用架构的设计。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Alphamilk

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值