第一章,概述
1.1 简述 Java 发展历程
Java 是 1991 年由在 Sun 公司任职的 James Gosling(Java 之父)领导开发,一开始名叫 Oak(一种橡树)语言,目的是为了在硬件设备上进行交互操作。后来在互联网的浪潮之下,Sun 公司敏锐地察觉到 Oka 在互联网开发上的应用前景,将该语言转向互联网开发领域,并在 1995 年注册更名为 Java。从 1996 开始,Java 开始了不断的版本迭代,比较著名的是 2004 年的 Java SE5.0(期间在 2009 年 Oracle 公司收购了 Sun 公司),直至现在(2022.12)Java 已经更新到 Java SE 19。
1.2 JVM、JRE、JDK 之间的关系
JVM(Java Virtual Machine)指 java 虚拟机,JRE(Java Runtime Environment)指 java 执行环境,JDK(Java Development Kit)指 java 开发工具包。JRE 由 Java SE API 和 JVM 组成,而 JDK 包括 JRE。
1.3 JCP、JSP、RI 和 TCK 之间的关系
JCP(Java Community Process)指 java 社区 进程,是一个开放性的国际组织,目的是为了让 Java 的演进能得到社区开发者的监督。JCP 由 JSR(Java Specification Request)、RI(Reference Implementation)、TCK(Technology Compatibility Kit)组成。简单地说,社区提出 JSR(新特性请求),JSR 经过 JCP 同意之后,进行开发得到 RI(代码参考),并且提供 TCK(工具包)作为技术兼容测试工具箱。
1.4 环境变量 JAVA_HOME、CLASSPATH、PATH 的作用
简单地说 JAVA_HOME 指向 JDK 的路径(\jdk),CLASSPATH 指向 JDK 下的工具包 lib 路径(\jdk\lib),PATH 指向 JDK 的 bin 路径(\jdk\bin)。
第一个环境变量指向 jdk 的安装目录,这样我们的开发软件 eclipse/IDEA 就可以找到我们安装好的 jdk 进而进行 Java 代码开发;
第二个环境变量顾名思义指的是类的路径,比如我们 import java.util 要使用这个现成的工具类,我们就会在这个环境变量路径下进行寻找;
第三个环境变量指向 Java 的指令运行目录,我们想要在终端里执行 Java 命令而且是在任何位置执行的话,我们就需要 JDK 的 bin 目录设置在计算机的 PATH 里。
第二章,标识符和数据类型
2.1 Java 程序结构
Java 程序宏观上是 package-class 型结构,一个 Java 项目由多个 package 包组成,每个 package 包由多个类组成(当然我们还习惯将一些类集中在一个文件中,这就让 package 下有某些文件下存在多个类,这无可厚非)。
微观上每个 Java 项目存在一个入口类或者说主类,该类下有一个 public static void main(String[] args) 方法作为入口 main 方法。通过该方法对所有的类进行实例化,统筹执行,以完成项目功能。其他类围绕入口类刻画自身功能,并和其他类通过关联/聚合/组合相互联系起来。
2.2 类、方法、常量和变量的命名约定
- 类:类名一般是名词或者名词性质短语,每个单词的首字母大写。例如:HelloWorld。
- 方法:方法名应该是动词或者动名词,首单词的首字母小写,其余单词首字母大写。例如:getName。
- 常量:简单类型常量的单词应该全部大写,单词之间通过下划线分割;对象常量可以使用混合大小写。例如:BLUE_COLOR。
- 变量:所有实例变量、类变量和全局变量的首单词的首字母为小写,后面单词首字母大写,变量名中最好不要使用下划线和美元符号。例如 orders, byPercent 。
2.3 自动类型转换和强制类型转换区别
- 转换位数方向不同:自动类型转换是从位数少的类型转为位数多的类型,而强制类型转换是从位数多的类型转换为位数少的类型。
- 使用方式不同:自动类型转换是在程序中悄然转换的,不需要用户自己声明处理;而强制类型转换必须在代码中声明,例如 int a=1;char b = (char)(a+‘a’);
- 强制类型转换会存在截断高位内容的情况,所以相比自动类型转换会导致精度下降或者数据溢出。
2.4 面向对象的概念和特征
- 概念:对象就是现实生活中实实在在存在的事物,是它自身特征和行为的结合体,计算机上称为属性(数据)和操作(方法)的结合体。计算机上的面向对象即编码基于对象的模式,创建对象式的代码而不是线性操作式的代码。
- 特征:三大特征——封装、继承、多态。封装就是将数据和数据的操作放在一起封装成一个类;继承就是保留一个类的属性和方法,并且加上自己特殊的属性和方法,从而构成一个新类,原来的类是父类,新类是子类,子类继承或派生于父类 ;多态:在一个类中或者具有父子关系的多个类中,让多个方法使用一个名字,从而具有多态性。
2.5 权限修饰符
- public : 修饰成员是共有的 , 它可以被其它任何对象访问 。
- private : 修饰成员只能被这个类本身访问 ,在类外或者子类都不能访问 。
- protected :修饰成员是受保护的 ,只能被类自身及其子类访问,即使子类在不同的包中仍然可以访问。
- 没有修饰: 如果没有访问修饰符 , 则表示 friendly , 成员可以被同一包中的各类访问。
2.6 关键字 static、extends、final、abstract、this、supper 的含义
- static:修饰类的属性和方法,使其成为静态成员,静态成员可以被类的所有对象共享。
- extends:继承关系
- final:用 final 修饰的类不能再派生子类。
- abstract:可以修饰类或者方法,表示被修饰成员是抽象的。抽象方法方法体是空的,而且必须是 public 或者 protected。而拥有抽象方法的类必须被定义为抽象类,但抽象类中也可以不包含抽象方法。
- this:指类自身。
- super:指父类。
第三章,表达式和流程控制语句
3.1 判断用户从键盘输入的整数是否为素数。素数是只能被 1 和本身整除的整数,换句话说,除了 1 和本身外,素数没有其它以因子
package practise;
import java.util.Scanner;
public class ThreeToOne {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("请输入正整数n:");
int n = input.nextInt();
input.close();
if(isPrime(n)){
System.out.println(n+"是素数!");
}else{
System.out.println(n+"不是素数!");
}
}
private static boolean isPrime(int num) {
for (int sun = 2; sun <= Math.sqrt(num); sun++) {
if (num % sun == 0) {
return false;
}
}
return true;
}
}
3.2 用户从键盘输入彩票号(一个 5 位且不含数字 0 的正整数),然后根据末尾号来判断是否中奖,如果末尾号为 1,3 和 9 为三等奖,如果末尾后 2 位是 29, 46 和 21 为二等奖,如果末尾后 3 位是 875, 326 和 596 为一等奖
package practise;
import java.util.Scanner;
public class TreeToTwo {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("请输入彩票号n(一个5位且不含数字0的正整数):");
int n = input.nextInt();
int[] list = new int[5];
input.close();
for (int i = 0; i < 5; i++) {
list[i] = n % 10;
n = n / 10;
if (list[i] == 0) {
System.out.println("数字含有0,错误!");
System.exit(1);
}
}
if (list[0] == 5 && list[1] == 7 && list[2] == 8 || list[0] == 6 && list[1] == 2 && list[2] == 3 || list[0] == 6 && list[1] == 9 && list[2] == 5) {
System.out.println("一等奖!");
} else if (list[0] == 9 && list[1] == 2 || list[0] == 6 && list[1] == 4 || list[0] == 1 && list[1] == 2) {
System.out.println("二等奖");
} else if (list[0] == 1 || list[0] == 3 || list[0] == 9) {
System.out.println("三等奖");
} else {
System.out.println("没有奖!");
}
}
}
3.3 一根绳子长 2000 米,每天截取其中的一半,问需要多少天绳子的长度会短于 5 米
package practise;
public class TreeToTree {
public static void main(String[] args) {
double length = 2000;
int day = 0;
while (length>=5) {
length = length/2;
day++;
}
System.out.println(day);
}
}
3.4 随机生成 100 个[1,100]区间内不重复的正整数,并在控制台中输出。
package practise;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class ThreeToFour {
public static void main(String[] args) {
Random ran = new Random();
List<Integer> myList = new ArrayList<>();
while (myList.size() <= 100){
int num = ran.nextInt(100)+1;
if(!myList.contains(num)){
myList.add(num);
System.out.println(num);
}
}
}
}
第四章,数组、字符串、容器
4.1 随机生成 10 个[1,100]区间内的正整数,利用冒泡排序法对这些数进行排序后输出
package practise;
import java.util.Random;
public class FourToOne {
public static void main(String[] args) {
Random random = new Random();
int[] numArr = new int[10];
for (int m = 0; m < numArr.length; m++) {
numArr[m] = random.nextInt(100) + 1;
}
int i, j;
for (i = 0; i < numArr.length; i++) {
for (j = 1; j < numArr.length - i; j++) {
if (numArr[j - 1] > numArr[j]) {
int temp;
temp = numArr[j - 1];
numArr[j - 1] = numArr[j];
numArr[j] = temp;
}
}
}
for (i = 0; i < numArr.length; i++) {
System.out.print(numArr[i] + " ");
}
}
}
4.2 从键盘输入字符串,统计字符串中包含的数字、字母和其它符号的个数
package practise;
import java.util.Scanner;
public class FourToTwo {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("请输入字符串:");
String s = input.nextLine();
input.close();
int num = 0;
int letter = 0;
int other = 0;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c >= '0' && c <= '9') {
num++;
} else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
letter++;
} else {
other++;
}
}
System.out.println("数字个数:"+num);
System.out.println("字母个数:"+letter);
System.out.println("其他字符个数:"+other);
}
}
第五章,进一步讨论对象和类
5.1 方法调用中按值传递和引用传递的区别
- 运用数据类型不同,按值传递是当参数为基本数据类型时的传递规则,引用传递是当参数是引用数据类型的传递规则。
- 按值传递是将实参的值拷贝给形参,实参和形参指向不同的内存空间,两者互不干扰。引用传递是将实参的地址传递给形参,实参和形参指向想用的内存空间,修改实参或者形参的值会影响另一个值。
5.2 方法重载与重写的区别
- 意义不同:通过方法重载来实现编译时的静态多态性,通过方法重写来实现运行时的动态多态性。
- 功能不同:方法重载目的是让不同的变量进行相同的操作(本质其实就是名字相同不用在方法起名上费力而已),方法重写是改写父类的方法体,本质是想对父类的方法内容进行修改以适应子类的特殊情况。
5.3 Java 的动态绑定机制
将一个方法与其所在的类关联起来就叫做方法的绑定,动态绑定是在程序运行时判断对象实际所属类型,根据实际类型调用其方法。它的机制其实很简单:一个对象在运行时,它的方法在父类或者父类的父类一直往上可能都有定义实现,究竟应该选择哪个定义来执行?Java 动态绑定机制就是向上递进寻找的逻辑,如果自身所属的类没有该方法的定义,就往这个类的父类上找定义,找不到再往上,直到找到为止。
5.4 静态成员变量和静态方法的含义
静态成员(变量/方法)指的就是在前面加上 static 修饰符,这种成员是隶属于类的成员,可以被类的所有对象共享。静态成员调用的时候通过类名.成员名调用。
5.5 终止类和终止方法的含义
终止类指的是被 final 修饰的类,这种类不能被继承。
终止方法指的是被 final 修饰的方法,这种方法不能被子类所重写。
5.6 抽象类与接口的区别
- 结构不同:抽象类中可以含有非抽象成员,而接口中的方法都是抽象方法。接口中只能有常量不能有变量 ,而抽象类中既可以有常量也可以有变量。
- 使用限制不同:抽象类和普通的类相同,都是一个类只能继承一个抽象类或者多重继承,但是一个类可以同时实现多个接口。而且如果一个类实现一个接口,但是没有重写接口中的所有方法,那么这个类必须是 abstract 类。
- 实现方式不同:抽象类通过其子类来实现抽象方法的功能,接口通过其实现类来实现抽象方法的功能。
5.7 静态成员类和非静态成员类的区别
- 静态类不能被实例化,非静态成员类可以。
- 静态类组成全是静态成员,而非静态类可以有静态成员也可以有非静态成员。
第六章,Java 语言中的异常
6.1 什么是异常?异常分为哪些种类。
异常(Exception) 是正常程序流程所不能处理或没有处理的异常情况或异常事件。例如 , 数组的下标越界 ,所要处理的文件不存在 ,网络连接中断 ,进行运算的操作数超出了指定的范围。
分类:
- 按照异常在编译时能否被检测来分:受检异常(在编译时能被 Java 编译器检测到)、非受检异常(在编译时不能被 Java 编译器检测到)
- 根据异常的严重性来分:程序可处理异常(通过修正程序还能继续执行)、错误异常(致命异常,不能简单地恢复执行,比如程序运行过程中内存耗尽)
6.2 Java 是如何处理异常的?
Java 异常处理有两种:捕获异常和转移异常。
捕获异常:通过 try-catch-finally 结构处理,try 运行代码,catch 捕获异常进行异常处理,finally 是即便出现异常也要执行的代码。
转移异常:程序不在当前方法内处理异常,而是把异常抛出到调用方法中。
第七章,Java 的图形用户界面设计
7.1 FlowLayout、BorderLayout、GridLayout 是如何安排组件的?
- FlowLayout:将组件逐个安放在容器的一行上,一行放满后就另起一个新行。
- BorderLayout:顶层容器窗格的默认布局管理器,每个由 BorderLayout 管理的容器被划分为东西南北中,在每个区域可以加入一个组件。
- GridLayout:网格式布局管理器,将容器划分为若干行乘若干列网格,组件依次放入其中,每个组件占据一格。
7.2 简述事件处理模型是如何处理事件的?事件监听程序的作用是什么?
首先将事件监听器注册到事件源上,当用户触发事件源上的事件之后,就会生成事件对象,之后触发事件监听器,事件被作为参数传入事件处理器,事件处理器做出响应。
事件监听程序的作用就是对事件源上是否发生行为进行监听,以判断什么时候发生了事件,进而调用事件处理器处理事件。
7.3 设计鼠标控制程序。程序运行时,如果在窗口中移动鼠标,窗口的底部将显示出鼠标的当前位置;如果移动鼠标的还按住 Ctrl 或 Shift 键,窗口底部会显示出 C 或 S;如果用户按下键盘上的键时,程序串口的底部显示出字母 D,当用户松开键盘上的键时,程序窗口的底部显示出字母 U。(代码和界面)
package practise;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class SevenToThree implements MouseMotionListener,KeyListener{
private JFrame frame;
private JTextField tf;
public static void main(String[] args){
SevenToThree that=new SevenToThree();
that.go();
}
public void go(){
frame=new JFrame("鼠标控制程序");
Container contentPane=frame.getContentPane();
contentPane.add(new Label(),BorderLayout.NORTH);
tf=new JTextField(50);
contentPane.add(tf,BorderLayout.SOUTH);
frame.addMouseMotionListener(this);
frame.addKeyListener(this);
contentPane.addKeyListener(this);
tf.addKeyListener(this);
frame.setSize(600,600);
frame.setVisible(true);
}
@Override
public void mouseDragged(MouseEvent e) {
}
@Override
public void mouseMoved(MouseEvent e) {
String s="The mouse x:"+e.getX()+",y:"+e.getY();
tf.setText(s);
}
@Override
public void keyTyped(KeyEvent e) {
tf.setText("D");
}
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode()==16){
tf.setText("S");
}
if(e.getKeyCode()==17){
tf.setText("C");
}
}
@Override
public void keyReleased(KeyEvent e) {
tf.setText("U");
}
}