简答题
Java 方法返回值能不能缺省?
-
Java 是一种强类型语言,方法在定义时必须明确指定返回值的类型。 这确保了类型安全和代码的可预测性.
-
方法返回值不能缺省。 必须显式声明返回类型.
-
如果方法没有返回值,需要使用
void
关键字来表示。void
意味着该方法执行某些操作但不返回任何值。
访问修饰符权限范围
-
private
< (默认/无修饰符) <protected
<public
-
private
权限:private
成员只能在声明它们的类中访问。 这提供了最高级别的封装. -
默认 (无修饰符) 权限 (也称为包访问权限): 默认权限允许在同一个包中的所有类访问该成员,但在不同包中的类不能访问.
-
protected
权限:protected
成员可以在同一个包中的所有类以及所有子类(无论子类是否在同一个包中)中访问. -
public
权限:public
成员可以从任何地方访问,包括同一个类、同一个包中的其他类、不同包中的类以及子类。 这是最宽松的访问级别.
什么是方法重载?
定义
在同一个作用域内,可以定义多个名称相同但参数列表不同的方法。编译器或解释器会根据调用方法时提供的参数的数量、类型或顺序来决定具体执行哪一个同名方法。
特点
-
同一个类中
-
方法名完全相同
-
参数类型或个数不同
-
返回值可以相同也可以不同【与返回值无关: 方法的返回值类型不同,不能作为方法重载的依据。】
阐述重载Overload 和重写Override 的区别。
表现形式不同:
- 重载:类中多态性的表现。
- 重写:父类与子类间多态性的表现。
定义位置不同:
- 重载:在同一个类中。
- 重写:在子类中。
方法签名要求:
- 重载:方法名相同,参数列表(个数或类型)必须不同。返回值类型可以不同。
- 重写:方法名、参数列表必须与父类完全相同。返回值类型通常也相同(或是父类返回值类型的子类)。
核心作用:
- 重载:允许方法有不同功能但名称相同,方便调用。
- 重写:子类根据需求重新实现父类方法,定义特定行为。
重载 (Overload) 和重写 (Override) 的共同点:
-
方法名必须相同
-
都是Java多态性的表现
Java 抽象类与接口
-
抽象类:
-
使用
abstract
关键字修饰的类,其中可以包含抽象方法(仅有方法声明,没有方法体),也可以包含普通方法和成员变量。 -
不能被实例化,即不能使用
new
关键字创建对象。 -
抽象类必须先派生出子类,再创建子类的实例化对象。
-
子类必须实现抽象类中所有的抽象方法(除非子类也是抽象类)。
-
-
接口:
-
使用
interface
关键字声明,接口中定义的方法默认是public
和abstract
的,变量默认是public
、static
和final
的。 -
接口不能被实例化,只能被
implements
-
一个类可以实现多个接口
-
实现接口的类必须实现接口的所有方法
-
接口可多继承接口。
-
-
抽象类与接口的区别
-
抽象程度:接口的抽象程度更高,只包含方法声明,没有任何实现细节;抽象类可以有部分方法的实现。【抽象类可包含非抽象方法,接口所有方法都是抽象的 (Java 8后可有默认方法和静态方法)。】
-
对应关系: 一个类只能继承一个抽象类,但可以实现多个接口。
-
成员变量:抽象类可以有各种类型的成员变量;接口中只能有静态常量(
public static final
修饰)。 -
构造方法 : 抽象类可以有,接口不能有。
-
方法访问修饰符:抽象类中抽象方法可以是 public, protected 或默认; 而接口中方法默认 public abstract。
-
抽象方法
定义
- 以abstract修饰的方法。
特点
- 只声明返回的数据类型、方法名称和所需的参数,没有方法体,
- 必须被子类的方法所重写,否则其子类的该方法仍然是abstract的,而这个子类也必须是抽象的,即声明为abstract。
- 抽象类中不一定包含抽象方法,但是包含抽象方法的类一定是抽象类。
什么是构造方法?构造方法的作用?构造方法的特点?定义构造方法时需要注意的事项?
定义
- 构造方法(或称构造器)是一种特殊的方法,用于创建和初始化对象。
- 与类同名的特殊方法,无返回类型 (void也不行),通常为public。
作用:
- 对象初始化:在创建对象时,为对象的成员变量(实例变量)赋初始值。
- 执行必要操作: 在对象创建时执行一些必要的操作,如分配资源、建立连接等。
特点
- 名称与类名相同
- 没有返回值类型
- 自动调用: 在使用 new 关键字创建类的实例时,构造方法会被自动调用。
- 不能直接调用: 不能像普通方法那样通过对象名或类名直接调用构造方法。
- 可重载: 一个类可以有多个构造方法,只要它们的参数列表不同(参数个数、类型或顺序不同),这称为构造方法重载。
- 默认构造方法: 如果类中没有显式定义任何构造方法,编译器会自动提供一个无参数的默认构造方法。如果类中定义了任何构造方法,则编译器不再提供默认构造方法。
定义构造方法时需要注意的事项:
- 构造方法可以有参数,也可以没有参数(无参构造方法)。
- 构造器Constructor 不能被继承,因此不能重写Overriding,但可以被重载Overloading。
- 若重载了有参构造方法,一定要先重载无参构造方法,再调用无参构造方法,否则会报错。
- 代码尽量简洁,仅用于初始化成员变量。
- 避免调用非final或非private的方法。
解释异常(Exception)定义、分类。
定义
- 异常 指程序运行时出现的不正常情况,需要捕获或处理。
分类
- 检查型异常 (Checked Exception):非运行时异常,编译期强制要求捕获处理。要么通过 throws 进行声明抛出,要么通过 try-catch 进行捕获处理,否则不能通过编译。
- 不可检查异常 (Unchecked Exception):指运行时异常 (Runtime Exception) 及其子类,并不会在编译期强制要求,通常是逻辑错误,可根据需要选择是否捕获。
阐述用户线程和守护线程。
用户线程 (User Thread):
- 运行在前台
- 程序主体: 用户线程是程序中执行主要任务的线程,例如执行核心业务逻辑。
- 阻止JVM退出:只要有任何用户线程在运行,Java虚拟机(JVM)就不会退出。
- 默认线程: 在Java中创建的线程默认是用户线程。
- 生命周期独立: 用户线程的生命周期独立于其他线程,直到其任务完成或被显式停止。
- main线程:Java程序的main方法运行在一个用户线程中。
守护线程 (Daemon Thread):
- 后台服务:运行在后台,辅助其他线程。
- 独立于控制终端: 它通常独立于用户交互界面或控制终端运行。
- 周期性任务/事件等待: 主要任务是周期性地执行某些任务或在后台等待处理特定事件。
- 不阻止JVM退出: 当所有用户线程都结束时,即使仍有守护线程在运行,JVM也会退出。 守护线程的退出不会影响JVM的退出。
- 生命周期依赖:依赖于用户线程。
- 服务于用户线程: 它的核心作用是为其他非守护线程(用户线程)提供服务。
- 使用方法: 通过 setDaemon(true) 设置,isDaemon() 判断。
- 资源释放: 不应持有需要关闭的资源(如打开文件),因为它们可能在没有执行
finally
块的情况下被终止。 - 创建新线程: 在守护线程中创建的新线程默认也是守护线程。
- 优先级: 通常具有较低的优先级。然而,对于线程调度器来说,在优先级相同的情况下,守护线程和用户线程被执行的概率是相同的。
- join()方法: 即使是守护线程,如果调用了
join()
方法,程序依然会等待该守护线程执行完毕。 - 典型例子: Java中的垃圾回收(GC)线程就是一个典型的守护线程。
请解释JDBC和ODBC
JDBC (Java DataBase Connectivity):
- Java语言编写的数据库连接API。
- 使Java程序能向数据库发送SQL,进行数据库操作。
- 跨平台,支持Java的平台均可运行。
ODBC (Open Database Connectivity):
- 微软提出的开放数据库互连标准。
- 解决异构数据库间数据共享问题。
- 基于Windows环境,提供统一接口访问不同DBMS。
什么是注解?注解的作用? @Override的作用?
定义
- 代码中的特殊标记,可在编译、类加载、运行时被JVM读取处理。
作用
- 不改变原有代码逻辑,在源码中嵌入补充信息。
- 使用前需要加@,用于修饰包,类,构造器,方法,成员变量,参数,局部变量的声明。
@Override 的作用
- 标记子类方法重写了父类方法。
- 提高可读性。
- 编译器校验父类中是否存在该方法。
Object 类
- 所有Java类的根父类。
- 包含一些通用方法,如 equals(), hashCode(), toString(), wait(), notify() 等。
匿名内部类
- 没有名字的内部类。
- 通常用于简化代码,尤其是在创建只需要使用一次的类实例时(如事件监听器)。
- 可以继承一个类或实现一个接口。
IO (输入/输出)
- 写文本文件:通常使用字符流 (如 FileWriter, BufferedWriter)。
- 写二进制文件:通常使用字节流 (如 FileOutputStream, BufferedOutputStream)。
集合 (List, Map, Set)
List (列表)
- 扩展 Collection 接口。
- 元素有序,可重复。
- 通过索引访问元素。
- 常用实现:ArrayList, LinkedList。
Set (集)
- 扩展 Collection 接口。
- 元素无序 (通常),不可重复。
- 根据 hashCode() 存放,通过 equals() 判断重复。
- 对equals和hashCode操作有更强的约定,如果两个Set对象包含同样的元素,二者便是相等的;
- 常用实现:HashSet, TreeSet。
Map (映射)
- 非 Collection 接口继承。
- 存储键值对 (key-value)。
- 键 (key) 不可重复,每个键最多映射一个值。
- 常用实现:HashMap, TreeMap。
面向对象编程的三大特性封装、继承和多态各有什么用处?
封装
- 隐藏内部细节: 将对象的状态(数据)和行为(方法)捆绑在一起,并对外部隐藏对象的内部实现细节。
- 提供接口: 只通过预定义的接口(如公有方法)与外部交互,控制对数据的访问。
- 提高安全性: 防止外部代码随意修改对象内部的重要数据,增强了代码的安全性和健壮性。
- 增强模块化和可维护性: 将代码组织成独立的模块,降低了模块间的耦合度,使得代码更容易理解、修改和维护。
继承
- 代码复用: 允许子类继承父类的属性和方法,从而避免重复编写相同的代码。
- 扩展性: 子类可以在继承父类的基础上,添加自己特有的属性和方法,或者重写父类的方法以实现特定的功能,从而扩展了现有代码的功能。
- 层级关系: 建立了类之间的 “is-a” (是一个)关系,有助于更好地组织和理解现实世界中的概念。
- 注意: 虽然继承可以实现代码复用,但也可能增加类之间的耦合度。过度或不恰当的继承可能导致代码结构复杂,难以维护。
多态
- “多种形态”: 允许不同类的对象对同一消息(方法调用)做出不同的响应。即同一个接口,可以有多种不同的实现方式。
- 灵活性和可扩展性: 使得程序在运行时能够根据对象的实际类型来执行相应的方法,提高了代码的灵活性和可扩展性。
- 接口重用: 允许使用父类类型的引用指向子类对象,并通过父类引用调用子类重写的方法,实现了接口的重用。
- 降低耦合: 有助于将接口与实现分离,降低了代码模块之间的依赖关系。
- 实现方式: 通常通过方法的重写(Override)和重载(Overload),以及抽象类和接口来实现。
总结
- 封装 是基础,它将数据和操作数据的代码捆绑起来,并保护数据不被外界随意访问。
- 继承 提供了代码复用和扩展的机制,允许创建具有层级关系的新类。
- 多态 增强了代码的灵活性和可扩展性,允许以统一的方式处理不同类型的对象。
多线程
- 允许程序同时执行多个任务。
- 实现方式:继承 Thread 类或实现 Runnable 接口。
- 涉及线程同步、通信、生命周期管理等。
数据库编程
- 通过JDBC等技术连接数据库。
- 执行SQL语句进行数据增删改查操作。
- 涉及事务管理、连接池等。
this关键字和super关键字分别代表什么?以及他们各自的使用场景和作用。
this 关键字
- 代表: 当前对象的引用。指的是当前正在执行代码的那个对象。
- 使用场景/作用:区分同名成员变量和局部变量、调用本类的其他构造方法、返回当前对象、作为参数传递
super 关键字
- 代表: 父类对象的引用。指的是当前对象的直接父类对象。
- 使用场景/作用:访问父类的成员变量、调用父类的成员方法、调用父类的构造方法
泛型 (Generics)
定义
在定义类、接口或方法时,不预先指定具体的类型,而是使用一个“类型参数”作为占位符。然后在创建对象或调用方法时,再传入实际的类型。
作用
- 编译时类型检查:将类型错误从运行时提前到编译时,提高了程序的健壮性。
- 消除类型转换:代码更简洁,可读性更好。
- 代码复用:可以编写更通用的算法和数据结构,适用于多种数据类型。
使用 final 声明的变量、方法和类的特点
变量
- 基本数据类型变量: 其值一旦被初始化后就不能再被修改。
- 引用数据类型变量: 其引用的对象地址一旦被初始化后就不能再指向其他对象,但对象本身的内容(如果可变)是可以修改的。
方法
- 不可覆盖 (Override): 子类不能覆盖(重写)父类中被 final 修饰的方法。
类
- 不可继承: 该类不能被任何其他类继承。
sleep() 与 wait() 的区别
归属不同:
- sleep():Thread 类的静态方法。
- wait():Object 类的方法。
锁的释放:
- sleep():不释放对象锁。
- wait():释放对象锁,线程进入等待池。
唤醒方式:
- sleep():时间到后自动恢复。
- wait():需通过同一对象的 notify() 或 notifyAll() 方法唤醒。
使用场景:
- sleep():线程暂停执行,不涉及对象锁竞争。
- wait():用于线程间协作,通常与 synchronized 和 notify/notifyAll 一起使用。
静态变量(static)有何特点?如何引用静态变量?
特点
- 类级别变量: 静态变量属于类,而不是类的任何特定实例(对象)。
- 内存中唯一: 在程序内存中,静态变量只有一份拷贝,被所有类的对象共享。
- 加载时机: 静态变量在类加载时被初始化,早于任何对象的创建。
- 生命周期: 静态变量的生命周期与类的生命周期相同,从类加载到虚拟机退出。
- 共享性: 任何对象都可以访问和修改同一个静态变量的值(如果可访问)。一个对象修改后,其他对象访问到的也是修改后的值。
引用方式
- 通过类名引用(推荐): 类名.静态变量名
- 通过对象名引用(不推荐,易误以为是实例变量):对象名.静态变量名
静态变量(类变量)和实例变量的主要区别
- 归属不同:
静态变量(类变量): 属于类本身,被类的所有实例共享。
实例变量: 属于类的每个具体实例(对象),每个实例都有一份独立的拷贝。 - 内存位置不同:
静态变量: 存储在方法区(或称为静态存储区)。
实例变量: 存储在堆内存中,随着对象的创建而分配空间。 - 生命周期不同:
静态变量: 随着类的加载而加载(初始化),随着类的卸载而销毁。其生命周期与类的生命周期一致。
实例变量: 随着对象的创建而创建,随着对象的销毁而被回收。其生命周期与对象的生命周期一致。 - 访问方式不同:
静态变量: 可以直接通过类名访问(推荐方式),也可以通过对象名访问(不推荐,易混淆)。
实例变量: 只能通过对象名访问。 - 副本数量:
静态变量: 只有一个副本,无论类创建了多少个实例。
实例变量: 每个实例都有自己的副本,不同实例之间的实例变量互不影响。
代码阅读题
已知数据库mydatabase中的表student如下,其中id为整型,name、sex为字符串型,数据库用户名为zyt,密码为pd12345,程序从数据库中读取所有记录并且输出。请填上空缺的代码。
id | name | sex |
---|---|---|
2013239 | 陈雪 | 女 |
2013397 | 王峰 | 男 |
2013421 | 刘菲雨 | 女 |
public class test{
public static void main(String args[]){
try{
// 加载 MySQL JDBC 驱动程序。在较新版本的 JDBC 中,这行可能不是必需的,
//因为驱动程序可以通过服务提供者机制自动加载。但为了确保兼容性,通常会显式加载。
Class.forName("com.mysql.jdbc.Driver");
//代码建立与数据库的连接。
Connection con=DriverManager.getConnection("jdbc:mysql://localhost:3306/mydatabase","zyt", "pd12345");
/*
jdbc:mysql://localhost:3306/mydatabase 是数据库的 URL。
jdbc:mysql: 表示使用 JDBC 连接 MySQL。
loca