第一章
过去学习编程语言的方法、经验和教训
- 方法:过去学习编程其实一直没什么自己的方法和思路,完全按照老师的安排走,完成老师的每周作业都比较困难。好在老师的安排都比较细致,但是对于课程外的知识,自己了解甚少。
- 经验和教训:各种编程语言都在不断发展,仅仅拘泥于课本的知识,是远远不够的,真正面对开发问题往往束手无策。但是课本的内容又及其重要,对初学者是不可或缺的知识。所以,学习编程应该在掌握课本的同时,不断扩展自己的视野,综合理论与实践。多刷题,锻炼自己的编程能力。
高级语言的编译型和解释型语言的编译执行过程有什么区别?
- 编译型语言不能跨平台,不同平台需要不同的版本;解释型语言可以跨平台,一个版本可以在不同的平台运行。
- 编译型语言先转换成可执行文件在执行,解释型语言一边解释一边执行。
- 编译型语言只需要向客户提供可执行文件,不需要提供源代码,安全性较高;解释型语言需要提供源代码,安全性较低。
JAVA语言都有哪些特点?与C、C++、python有哪些不同?
- Java语言的特点
- 可移植性
- 面向对象
- 多线程
- 简单安全
- 分布性
- 区别
- C++、Java、python都是面向对象的语言,但C++和Java是强类型语言,python是一种弱类型语言。
- Java的垃圾回收机制。C++需要程序员收到回收。
Java实现跨平台的原理
Java程序是通过java虚拟机在系统平台上运行的,只要该系统可以安装相应的java虚拟机,该系统就可以运行java程序。
Java跨平台原理
由源文件(.java)—>字节码文件(.class)(二进制文件)-----> 解释---->Unix,Win,Linux等机器。
JDK、JRE、JVM分别是什么的简称?它们之间有什么联系和区别?
- JDK JDK(Java SE Development Kit),Java标准开发包,它提供了编译、运行Java程序所需的各种工具和资源,包括Java编译器、Java运行时环境,以及常用的Java类库等。
- JRE JRE( Java Runtime Environment) 、Java运行环境,用于解释Java字节码文件
- JVM JVM(Java Virtual Mechinal),Java虚拟机,是JRE的一部分。它是整个java实现跨平台的最核心的部分,负责解释执行字节码文件,是可运行java字节码文件的虚拟计算机。
区别与联系
- JDK 用于开发,JRE 用于运行java程序 ;如果只是运行Java程序,可以只安装JRE,无序安装JDK。
- JDk包含JRE,JDK 和 JRE 中都包含 JVM。
- JVM 是 java 编程语言的核心并且具有平台独立性。
第二章
1.Java包含哪两大数据类型?其中基本数据类型的每种类型的取值范围和默认值是多少?
Java的数据类型:基本类型和复合类型
基本类型:
2.Java在什么情况下会发生整型溢出?请举例说明,并给出解决方案。
整型(int)溢出指的是:一个数字不在整型的取值范围内,比如2^100,值太大了,int接受不了,就溢出。
一个简单的方式是使用long,这种数据类型可表示的范围比int大。
还有一个简单的方式是使用 BigInterger 类,该类是大整数类,可以储存任意长度的整数
3.Java基本类型的包装类分别是哪些?其高频区间数据缓存范围分别是什么?请选择一种包装类型编程验证其数据缓存特性。
第四章
对象与对象引用的区别
- 当对象的引用变量指向对象时,他们两就联系起来,改变引用的属性,就会改变对象的属性;
- 如果同一个对象被多个引用变量引用的话,则这些引用变量将共同影响这个对象本身。
对象作为参数传递的特点是什么?
- 基本数据类型作为参数在方法中的传递是值传递
public class daytime {
private static int a;
public static void main(String [] args) {
modify(a);
System.out.println(a);
}
public static void modify(int a) {
a++;
}
}
- 对象作为参数传递时,传递的是对象的地址
class IntClass {
int value;
}
public class RunIntClass {
public static void modifyValue(IntClass s, int val){
s.value = val;
}
public static void main(String[] args) {
IntClass a = new IntClass();
modifyValue(a,8);
System.out.println(a.value);
}
}
对象初始化的顺序是怎样的?
- 初始化父类的静态代码
- 初始化子类的静态代码
- 初始化父类的非静态代码
- 初始化父类构造函数
- 初始化子类非静态代码
- 初始化子类构造函数
类的static字段与非static字段的区别
关于static和非static变量的区别。
static 修饰的变量称为类变量或全局变量或成员变量,在类被加载的时候成员变量即被初始化,与类关联,只要类存在,static变量就存在。非static修饰的成员变量是在对象new出来的时候划分存储空间,是与具体的对象绑定的,该成员变量仅为当前对象所拥有的。
static修饰的变量在加载的时候先于main方法加载在内存中的数据共享区-------方法区,而非static的变量在加载的时候,是要创建变量才加载在堆内存中的。
一个static变量单独划分一块存储空间,不与具体的对象绑定在一起,该存储空间被类的各个对象所共享。static变量值在方法区加载一次,而非static在创建对象时会加载很多次。每次创建都会拷贝一份。
对象在引用成员变量是直接通过类名.变量名调用,对象在引用实例变量时只能通过对象名.变量名调用。
在类中调用成员变量时直接调用或者以类名.变量名方式调用,实例变量则用this或者直接调用。
关于static方法和非static方法的区别
6. static修饰的方法也和static一样。先于main方法被加载到方法区,以便共享使用。
静态的static方法中不能使用this或者super关键字,因为static方法是先于对象创建之前就已经加载的方法,是属于类的方法,而this和super指向的是本类的对象或者父类的对象,非静态的方法是属于对象的,方法里可以用this和super。
static方法可以用对象.方法名来调用,也可以用类名.方法名来调用。而非静态的方法只能创建对象后时调用。
static方法是加载一次,被所有的对象所共享。而非静态方法是有多少个对象就拷贝多少次,每个对象只能调用自己的拷贝的方法。
对象调用非静态的方法时,不考虑线程安全性的问题,而调用静态方法时,要考虑安全性的问题。因为静态方法只有一份。而对象的方法是自己有自己的。
同一个类中,静态方法中只能访问类中的静态成员。而非静态方法可以访问非静态的方法(使用类名调用,或者创创建本类的对象调用)。
Java中final修饰符有什么作用
final修饰类属性则属性为常量,final修饰类方法则该方法在子类当中不能被覆盖,可防止任何继承类修改此方法,保证了程序的安全性和正确性
第五章
1.Java的访问控制修饰符有哪些?
Java有四种访问权限, 其中三种有访问权限修饰符,分别为private,public和protected,还有一种不带任何修饰符。
private: Java语言中对访问权限限制的最窄的修饰符,一般称之为“私有的”。被其修饰的类、属性以及方法只能被该类的对象访问,其子类不能访问,更不能允许跨包访问。
default:即不加任何访问修饰符,通常称为“默认访问模式“。该模式下,只允许在同一个包中进行访问。
protect: 介于public 和 private 之间的一种访问修饰符,一般称之为“保护形”。被其修饰的类、属性以及方法只能被类本身的方法及子类访问,即使子类在不同的包中也可以访问。
public: Java语言中访问限制最宽的修饰符,一般称之为“公共的”。被其修饰的类、属性以及方法不仅可以跨类访问,而且允许跨包(package)访问。
2.子类对于父类继承的哪些属性和方法是可见的?
子类在继承父类的时候,首先应该满足父类可被访问,例如当子类和父类不在同一个包当中时,父类修饰符必为public;在父类能被访问的前提下,凡是修饰符为public或是protected的父类属性成员或方法能被子类访问;private的属性成员或是方法则不能被直接访问。子类不能直接访问父类的private属性和方法,可以调用父类的公共方法来间接访问私有属性。
public class Father {
private int father1 = 1;
private void getFather1()
{
System.out.println("father1: "+father1);
}
protected int father2 = 2;
protected void getFather2()
{
System.out.println("father2: "+father2);
}
public int father3 = 3;
public void getFather3()
{
System.out.println("father3: "+father3);
}
}
public class Son extends Father{
public static void main(String[] args) {
Son son = new Son();
int son1 = son.father1;
int son2 = son.father2;
int son3 = son.father3;
son.getFather1();
son.getFather2();
son.getFather3();
}
}
//此时程序会出现错误,错误原因如下:
//'father1' has private access in 'Father'
//'getFather1()' has private access in 'Father'
3.什么是组合?什么是重载?有什么作用?
组合:一个类的对象引用是另一个类的属性就是一个组合现象。
作用:实现代码的复用;使对象间的耦合性较为松散,比如: 假设有一个类A,另一个类的对象引用fp是它的属性,当外界的变化使fp所指向的对象损坏时,我们可以灵活地将fp指向另一个对象。
重载:在类中定义了多个同名而不同内容参数的成员方法时,称这些方法是重载方法。
作用:可以实现程序的消息处理接口方法的扩充,同时保留旧的接口方法保障原先使用程序的稳定。
4.什么是覆写?有什么作用?
多态:子类对父类参数相同、返回值类型相同的同名方法重新定义,这种多态被称为覆盖。
作用:方法覆盖与引用替换相结合,可使抽象类的声明在保证消息发送统一的前提下,具有消息结果执行上的相异性特点。
class Parent {
public int getScore(){
return 1;
}
}
class Son {
public int getScore(){
return 2;
}
}
第六章
如何实现两个对象之间互发消息
对象和对象引用好比生活中电视机与遥控器的关系,遥控器是采用红外线的方式控制电视,而引用控制对象采用的则是发消息的方式。使用引用的属性或方法其实都是调用对象的属性和方法,而消息概念的引入就是说明这样的一个过程。因此,消息的实质就是引用向对象发出的服务请求,是数据成员和成员方法的调用。例如fp.name和fp.fire()就是发送消息。
组合与继承的区别以及两者的使用场景
组合与继承的区别:
继承是子类继承父类,父类的所有属性和方法都可以被子类访问和调用。组合是指将已存在的类型作为一个新建类的成员变量类型,两个类之间无上下级关系。
使用场景:
当你只需要使用另外一个类的方法时使用组合。但是如果你需要使用另外一个类的作用时但你不想被其他的类访问用继承。
Java中的运行时多态的含义是什么?有什么作用?
运行时多态:当同一个引用变量(父类引用)指向不同的子类实例,然后访问引用变量成员方法, 方法会有不同的表现。换句话说,运行时多态就是重写,就是子类方法重写了父类方法。使用父类引用指向子类对象,再调用某一父类中的方法时,不同子类会表现出不同结果。
作用:运行时多态性提供了更大的灵活性,因为所有事情都在运行时得到解决。
举例说明运算符instanceof的使用场景
public interface A {
}
public class B implements A{
}
public class C extends B{
}
public class InstanceofTest3 {
public static void main(String[] args) {
A a = null;
B b = null;
boolean result;
result = a instanceof A;
System.out.println(result); // 结果:false null用instanceof跟任何类型比较时都是false
result = b instanceof B;
System.out.println(result); // 结果:false null用instanceof跟任何类型比较时都是false
a = new B();
b = new B();
result = a instanceof A;
System.out.println(result); // 结果:true a是接口A的实例对象引用指向子类类B,类B实现了接口A,所以属于同一个继承树分支
result = a instanceof B;
System.out.println(result); // 结果:true a是接口A的实例对象引用指向子类类B,类B实现了接口A,所以属于同一个继承树分支
result = b instanceof A;
System.out.println(result);// 结果:true b是类B的实例对象,类B实现了接口A,所以属于同一个继承树分支
result = b instanceof B;
System.out.println(result);// 结果:true b是类B的实例对象,类B实现了接口A,所以属于同一个继承树分支
B b2 = new C();
result = b2 instanceof A;
System.out.println(result); // 结果:true b2是父类B引用指向子类C,类B实现了接口A,所以属于同一个继承树分支
result = b2 instanceof B;
System.out.println(result); // 结果:true b2是父类B引用指向子类C,所以属于同一个继承树分支
result = b2 instanceof C;
System.out.println(result); // 结果:true b2是父类B引用指向子类C,所以属于同一个继承树分支
}
}
谈谈抽象类与接口的异同以及两者的使用场景
- 相同点:
两者都是抽象类, 都不能实例化.
继承两者的类或者接口, 都必须要实现已经声明的抽象方法. - 不同点:
抽象类使用 extends , 接口使用 implements .
类只有单继承, 接口可以多个.
接口只能定义 public 方法,public final static 变量.
类可以有缺省或者默认方法,接口不行. - 使用场景:
抽象类强调继承关系.
接口偏于功能的实现.
第七章
Throwable的子类包含哪两类?简述Java Error类与Exception类的区别
-
Throwable子类:
-
Error:
致命异常,标识系统发生了不可控的错误。程序无法处理,只能人工介入。例如,虚拟机产生了StackOverflowError,OutOfMemoryError。 -
Exception:
非致命异常。程序可处理。分为受编辑器检测的checked异常(受检异常)和不受编辑器检测的unchecked异常(非受检异常)
-
Exception又分为checked异常和unchecked异常,请分别举例说明
将派生于Error或者RuntimeException的异常称为unchecked异常,所有其他的异常成为checked异常。
- unchecked异常
public class TestArray {
private static int[] x;
public static void main(String[] args){
System.out.println(x[0]);
}
}
//该程序会出现一下提示信息:
//Exception in thread "main" java.lang.NullPointerException
//at TestArray.main(TestArray.java:4)
- checked异常
import java.io.*;
class Example {
public static void main(String args[]) throws IOException
{
FileInputStream fis = null;
fis = new FileInputStream("B:/myfile.txt");
int k;
while(( k = fis.read() ) != -1)
{
System.out.print((char)k);
}
fis.close();
}
}
//输出结果为:File content is displayed on the screen.
简述StackOverflowError和OutOfMemoryError两类错误的发生情形和原因
-
StackOverFlowError(栈溢出)
-
原因: 线程请求的栈深度大于虚拟机所允许的最大深度
-
发生情形: 由于递归发生在一个单独的线程当中,当递归的深度增加时,递归栈的深度会增加,当应用程序递归得太深时,就会发生栈溢出。
-
-
OutOfMemoryError(内存溢出)
-
原因: 当Java虚拟机因对象内存不足而无法分配对象,垃圾收集器无法提供更多内存时抛出。
-
发生情形: 当内存不足时,就会抛出该异常。
-
简述异常处理的两种方式,并举例说明区别
- 声明抛出处理:声明抛出也分为隐式和显式两种方式。
- 隐式声明抛出:异常类型是RuntimeException或者是其子类,程序可以对异常不作任何声明与处理。
- 显式声明抛出:对异常进行声明处理,当编译遇到该类型的异常时就会抛出。注意:当子类覆盖父类的方法时,子类抛出的异常类型应和父类抛出的异常相同或为其子类,不能为其父类。也就是子类抛出的异常范围应该更小、更精确。
隐式申明抛出
package bookcode.ex7.part7_5;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class ioEXception {
private static int[] x;
public static void main(String[] args) {
// 隐式
System.out.println(x[0]);
String foo = args[1];
System.out.println("foo = " + foo);
}
}
/* 发生异常时并没有在main()方法中进行任何抛出异常的处理操作,直接main()的Java虚拟机中去处理异常,抛出以下异常:
Exception in thread "main" java.lang.NullPointerException
at bookcode.ex7.part7_5.ioEXception.main(ioEXception.java:12)*/
显式声明抛出
package bookcode.ex7.part7_5;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class ioEXception {
public static void main(String[] args) throws IOException {//显式声明抛出
BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
String c1;
int i = 0;
String[] e = new String[10];
while (i < 10) {
c1 = keyin.readLine();
e[i] = c1;
i++;
}
}
}
捕获处理
package bookcode.ex7.part7_5;
public class ioEXception {
public static void main(String args[]) {
try {
int a[] = new int[2];
System.out.println("Access element three :" + a[3]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Exception thrown :" + e);
}
System.out.println("Out of the block");
}
}
根据某业务场景自定义一个异常类,并在某场景下抛出该异常对象
public class yicang extends Exception{
yicang(String ms){
super(ms);
}
static void Throw() throws yicang {
int a=0,b=3;
if(a!=0) {
System.out.println(b/a);
}
else{
throw new yicang("除数不能为0");
}
}
public static void main(String []args) {
try
{Throw();}
catch(yicang e) {
e.printStackTrace();
}
}
异常中的throws声明与throw语句的区别是什么?
-
throw:
- 表示方法内抛出某种异常对象
-
throws:
- 方法的定义上使用 throws 表示这个方法可能抛出某种异常
finally子句的作用是什么?
在java中finally首先必须使用在所有catch的最后位置, 无论是否抛出异常,finally代码块总是会被执行。就算是没有catch语句同时又抛出异常的情况下,finally代码块任然会被执行。finally代码块主要用来释放资源,比如:I/O缓冲区,数据库连接。
第九章
Future Task类有什么作用?它实现了哪些接口?Callable接口和Runnable接口有什么不同?
FutureTask可用于异步获取执行结果或取消执行任务的场景。通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过FutureTask的get方法异步获取执行结果,因此,FutureTask非常适合用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。另外,FutureTask还可以确保即使调用了多次run方法,它都只会执行一次Runnable或者Callable任务,或者通过cancel取消FutureTask的执行等。
-
接口
- Runnable接口
- Future接口
- RunnableFuture接口
-
Callable接口和Runnable接口有什么不同?
- Callable要实现call方法,Runnable要实现run方法
- call方法可以返回值,run方法不能
- call方法可以抛出checked exception,run方法不能
volatile关键字有什么作用?
- 保证了不同线程对共享变量进行操作时的可见性,即一个线程修改了共享变量的值,共享变量修改后的值对其他线程立即可见
- 通过禁止编译器、CPU 指令重排序和部分 happens-before 规则,解决有序性问题
编写Java程序模拟烧水泡茶最优工序
/*
这个模拟程序一共分为三个时间,烧开水,洗茶杯,泡茶
烧开水的时候可以洗茶杯
必须烧完开水,洗完茶杯以后才能开始泡茶
*/
import java.util.Date;
public class Tea implements Runnable{
static Date date = new Date();
public static void main(String[] args) throws Exception{
HeatUpWater h1 = new HeatUpWater();
WashCup w1 = new WashCup();
Tea m1 = new Tea();
Thread t1 = new Thread(h1);
Thread t2 = new Thread(w1);
Thread t3 = new Thread(m1);
try{
t1.start();
t2.start();
t2.join();
t1.join();
}catch (Exception e){
System.out.println("Error!");
}
t3.start();
}
public void run(){
System.out.println(date+" 正在泡茶");
try{
Thread.sleep(1000);
}catch (Exception e){
}
}
}
class HeatUpWater implements Runnable{
static Date date = new Date();
public void run(){
int time = 10;
while(time != 0){
System.out.println(date+" 正在烧水");
time--;
try{
Thread.sleep(1000);
}catch (Exception e){
System.out.println("Heat up water is in the Error!");
}
}
}
}
class WashCup implements Runnable{
static Date date = new Date();
public void run(){
int time = 5;
while(time != 0){
System.out.println(date+" 正在洗茶杯");
time--;
try{
Thread.sleep(1000);
}catch (Exception e){
}
}
}
}
第十五章
编写完整的基于Socket的多客户、服务器通信程序
//ServerThread.java
import java.io.*;
import java.net.*;
public class ServerThread extends Thread{
Socket socket=null;
int clientnum; //保存本进程的客户序号
public ServerThread(Socket socket,int num) {
this.socket=socket;
clientnum=num+1;
}
public void run() { //线程主体
try{
String line;
BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter os=new PrintWriter(socket.getOutputStream());
BufferedReader sin=new BufferedReader(new InputStreamReader(System.in));
System.out.println("Client:"+ clientnum +is.readLine());
line=sin.readLine();
while(!line.equals("bye")){
os.println(line);
os.flush();
System.out.println("Server:"+line);
System.out.println("Client:"+ clientnum +is.readLine());
line=sin.readLine();
}
os.close();
is.close();
socket.close();
}catch(Exception e){
System.out.println("Error:"+e);
}
}
}
//TalkClient.java
import java.io.*;
import java.net.*;
public class TalkClient {
public static void main(String args[]) {
try{
//向本机的4700端口发出客户请求
Socket socket=new Socket("127.0.0.1",4800);
BufferedReader sin=new BufferedReader(new InputStreamReader(System.in));
PrintWriter os=new PrintWriter(socket.getOutputStream());
BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream()));
String readline;
readline=sin.readLine();
while(!readline.equals("bye")){
os.println(readline);
os.flush();
System.out.println("Client:"+readline);
System.out.println("Server:"+is.readLine());
readline=sin.readLine();
}
os.close();
is.close();
socket.close();
}catch(Exception e) {
System.out.println("Error"+e);
}
}
}
//MultiTalkServer.java
import java.io.*;
import java.net.*;
import ServerThread;
public class MultiTalkServer{
static int clientnum=0; //记录当前客户的序号
public static void main(String args[]) throws IOException {
ServerSocket serverSocket=null;
try{
serverSocket=new ServerSocket(4800);
}catch(IOException e) {
System.out.println("Could not listen on port:4700.");
System.exit(-1); //退出
}
while(true){
new ServerThread(serverSocket.accept(),clientnum).start();
clientnum++;
}
serverSocket.close();
}
}
第十章
Java集合框架中的各种常用类的基本操作
1、vector
从AbstractList派生而来,可自动增加容量来容纳所需对象,实现List接口,元素之间有序
import java.util.*;
public class vector {
public static void main(String[] args) {
Vector<Integer> v=new Vector();
for(int i=1;i<=10;i++)//添加元素
v.addElement(new Integer(i));
for(Iterator it=v.iterator();it.hasNext();) {//遍历元素
Integer i=(Integer) it.next();
System.out.print(i+" ");
}
System.out.println();
v.remove(3);//删除元素
for(Iterator it=v.iterator();it.hasNext();) {
Integer i=(Integer) it.next();
System.out.print(i+" ");
}
System.out.println();
}
}
2、Stack
从vector中派生,增加了栈的实现方法
import java.util.*;
public class stack {
public static void main(String[] args) {
Stack<Integer> s=new Stack();
for(int i=0;i<10;i++)//入栈
s.push(new Integer(i));
s.add(new Integer(10));//添加
for(Iterator it=s.iterator();it.hasNext();) {//遍历
System.out.print((Integer)it.next()+" ");
}
System.out.println();
s.remove(3);//删除
for(Iterator it=s.iterator();it.hasNext();) {
System.out.print((Integer)it.next()+" ");
}
System.out.println();
s.pop();//出栈
for(Iterator it=s.iterator();it.hasNext();) {
System.out.print((Integer)it.next()+" ");
}
System.out.println();
while(!s.empty()) {
System.out.print(s.pop()+" ");
}
}
}
3、LinkedList
从AbstractList派生而来,实现了一个链表,由这个类定义的链表也可以像栈和队列一样被使用。
package chapter10;
import java.util.*;
public class linkedlist {
public static void main(String[] args) {
LinkedList<Integer> l=new LinkedList();
for(int i=0;i<5;i++)//从头添加
l.addFirst(new Integer(i));
for(int i=5;i<10;i++)//从尾添加
l.addLast(new Integer(i));
for(Iterator it=l.iterator();it.hasNext();) {//遍历
System.out.print((Integer)it.next());
}
System.out.println();
l.removeFirst();//从头删
l.removeLast();//从尾删
for(Iterator it=l.iterator();it.hasNext();) {//遍历
System.out.print((Integer)it.next());
}
System.out.println();
}
}
4、ArrayList
由AbstractList派生而来,规模可变,且能像链表一样被访问。
import java.util.*;
public class arraylist {
public static void main(String[] args) {
ArrayList<Integer> al=new ArrayList();
for(int i=1;i<=10;i++)//增加元素
al.add(new Integer(i));
for(Iterator it=al.iterator();it.hasNext();)//遍历元素
System.out.print((Integer)it.next()+" ");
System.out.println();
al.remove(4);//删除元素
for(Iterator it=al.iterator();it.hasNext();)
System.out.print((Integer)it.next()+" ");
}
}