1.接口和抽象类的区别
相似点:
(1)接口和抽象类都不能被实例化
(2)实现接口或继承抽象类的普通子类都必须实现这些抽象方法
不同点:
(1)抽象类可以包含普通方法和代码块,接口里只能包含抽象方法,静态方法和默认方法,
(2)抽象类可以有构造方法,而接口没有
(3)抽象类中的成员变量可以是各种类型的,接口的成员变量只能是 public static final 类****型的,并且必须赋值
2.重载和重写的区别
重载发生在同一个类中,方法名相同、参数列表、返回类型、权限修饰符可以不同
重写发生在子类中,方法名相、参数列表、返回类型都相同,权限修饰符要大于父类方法,声明异常范围要小于父类方法,但是final和private修饰的方法不可重写
3.==和equals的区别
==比较基本类型,比较的是值,
==比较引用类型,比较的是内存地址
equlas是Object类的方法,本质上与==一样,但是有些类重写了equals方法,比如String的equals被重写后,比较的是字符值,另外重写了equlas后,也必须重写hashcode()方法
疑问?
>为什么重写equal了必须重写hashcode?
equals() 方法和 hashcode() 方法是 java.lang.Object 类的两个重要的方法,Java中多数类都会重写 Object 类的 equals() 方法。
在实际应用中,如果我们自定义的类需要进行比较操作,就一定也需要重写 equals() 方法。那么为什么重写 equals()方法时,必须要求重写 hashCode() 方法呢?
首先, equals() 方法和 hashcode() 方法间的关系是这样的:
1、如果两个对象相同(即:用 equals 比较返回true),那么它们的 hashCode 值一定要相同;
2、如果两个对象的 hashCode 相同,它们并不一定相同(即:用 equals 比较返回 false);
上面这两句话,如果明白【散列表】的结构,就一定会很明白,这里只简单提一句:散列表同时运用了数组和链表。
《Effective java》一书中这样说到:在每个覆盖了 equals() 方法的类中,也必须覆盖 hashCode() 方法,如果不这样做的话,就会违反 Object.hashCode 的通用的约定,从而导致该类无法结合所有基于散列的集合一起正常运作,这样的集合包括HashMap,HashSet 和 HashTable。
如果只重写了 equals 方法,那么默认情况下,Set 进行去重操作时,会先判断两个对象的 hashCode 是否相同,此时因为没有重写 hashCode 方法,所以会直接执行 Object 中的 hashCode 方法,而 Object 中的 hashCode 方法对比的是两个不同引用地址的对象,所以结果是 false,那么 equals 方法就不用执行了,直接返回的结果就是 false:两个对象不是相等的,于是就在 Set 集合中插入了两个相同的对象。
但是,如果在重写 equals 方法时,也重写了 hashCode 方法,那么在执行判断时会去执行重写的 hashCode 方法,此时对比的是两个对象的所有属性的 hashCode 是否相同,于是调用 hashCode 返回的结果就是 true,再去调用 equals 方法,发现两个对象确实是相等的,于是就返回 true 了,因此 Set 集合就不会存储两个一模一样的数据了,于是整个程序的执行就正常了。
总结
hashCode 和 equals 两个方法是用来协同判断两个对象是否相等的,采用这种方式的原因是可以提高程序插入和查询的速度,如果在重写 equals 时,不重写 hashCode,就会导致在某些场景下,例如将两个相等的自定义对象存储在 Set 集合时,就会出现程序执行的异常,为了保证程序的正常执行,所以我们就需要在重写 equals 时,也一并重写 hashCode 方法才行。
答案来源
4.Java异常处理机制
4.1Error和Exception的区别:
Error和Exception都有一个共同的根类是Throwable类。
Error是系统中的错误,程序员是不能改变的和处理的,一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢等。对于这类错误的导致的应用程序中断,仅靠程序本身无法恢复和和预防,遇到这样的错误,建议让程序终止。因此我们编写程序时不需要关心这类错误。
Exception,也就是我们经常见到的一些异常情况,表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。
异常分类
总体上我们根据Javac对异常的处理要求,将异常类分为2类。
我们常说的异常是狭义上的:就是指Exception及其子类,但是广义上的异常是包括Exception和Error;
Java的异常(包括Exception和Error)从广义上分为检查异常(checked exceptions)和非检查的异常(unchecked exceptions)。
其中根据Exception异常进行划分,可分为运行时异常和非运行时异常。
需要明确的是:检查和非检查是对于javac来说的,这样就很好理解和区分了。
检查异常
What:什么是检查异常(checked exception)?
就是编译器要求你必须处置的异常。不知道你编程的时候有没有遇到过,你写的某段代码,编译器要求你必须要对这段代码try…catch,或者throws exception,如果你遇见过,没错,这就是检查异常,也就是说,你代码还没运行呢,编译器就会检查你的代码,会不会出现异常,要求你对可能出现的异常必须做出相应的处理。
javac强制要求程序员为这样的异常做预备处理工作(使用try…catch…finally或者throws)。在方法中要么用try-catch语句捕获它并处理,要么用throws子句声明抛出它,否则编译不会通过。这样的异常一般是由程序的运行环境导致的。因为程序可能被运行在各种未知的环境下,而程序员无法干预用户如何使用他编写的程序,于是程序员就应该为这样的异常时刻准备着。如SQLException , IOException,ClassNotFoundException 等。
比如:我们调用日期格式化类解析字符串的时候;
How:怎样处理检查异常(checked exception)?
1、继续抛出,消极的方法,一直可以抛到java虚拟机来处理,就是通过throws Exception抛出。
2、用try...catch捕获
注意,对于检查的异常必须处理,或者必须捕获或者必须抛出
Where:检查异常有哪些呢?
除了RuntimeException与其子类,以及错误(Error),其他的都是检查异常(绝对的大家族)。
非检查异常
What:什么是非检查异常(unchecked exceptions)?
编译器不要求强制处置的异常,虽然你有可能出现错误,但是编译器不会在编译的时候检查,没必要,也不可能。
javac在编译时,不会提示和发现这样的异常,不要求在程序处理这些异常。所以如果愿意,我们可以编写代码处理(使用try…catch…finally)这样的异常,也可以不处理。
对于这些异常,我们应该修正代码,而不是去通过异常处理器处理。这样的异常发生的原因多半是代码写的有问题。如除0错误ArithmeticException,错误的强制类型转换错误ClassCastException,数组索引越界ArrayIndexOutOfBoundsException,使用了空对象NullPointerException等等。
How:对非检查的异常(unchecked exception )怎样处理?
1、用try...catch捕获
2、继续抛出
3、不处理
4、通过代码处理
一般我们是通过代码处理的,因为你很难判断会出什么问题,而且有些异常你也无法运行时处理,比如空指针,需要人手动的去查找。
而且,捕捉异常并处理的代价远远大于直接抛出。
Why:为什么有非检查异常?
你想想非检查异常都有哪些?
NullPointerException,IndexOutOfBoundsException,VirtualMachineError等,这些异常你编译的时候检查吗?再说了,明明可以运行时检查,都在编译的时候检查,你写的代码还能看吗?而且有些异常只能在运行时才能检查出来,比如空指针,堆溢出等。
Where:非检查异常有哪些?
RuntimeException与其子类,以及错误(Error)。
Exception异常划分
Exception异常进行划分,它可分为运行时异常和编译期异常。
运行时异常:
是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是非检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。
编译期异常:
是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不要自定义检查异常。
4.2常见异常
java.lang.RuntimeException: 运行时异常
ClassCastException: 类类型转换异常,当试图将对象强制转换为不是实例的子类时,抛出该异常;
ArrayIndexOutOfBoundsException: 数组下标越界异常,当你使用不合法的索引访问数组时会抛出该异常;
NullPointerException: 空指针异常,通过null进行方法和属性调用会抛出该异常;
ArithmeticException: 算术运算异常,除数为0,抛出该异常;
NumberFormatException: 数字转换异常,当试图将一个String转换为指定的数字类型,而该字符串确不满足数字类型要求的格式时,抛出该异常;
InputMismatchException: 输入不匹配异常,输入的值数据类型与设置的值数据类型不能匹配。
4.3异常处理的处理机制
在编写程序时,经常要在可能出现错误的地方加上检测的代码,如进行x/y运算时,要检测分母为0,数据为空,输入的不是数据而是字符等。过多的if-else分支会导致程序的代码加长、臃肿,可读性差。因此采用异常处理机制。
在编写代码处理异常时,对于检查异常/非检查异常,都有2种不同的处理方式:
1、使用try...catch...finally语句块处理它。
2、在函数签名中使用throws 声明交给函数调用者caller去解决。
比如现有一辆车,这个车你可以是方法,这辆车在可能存在各种风险,那么对于这些风险的处理方式,就相当于异常的处理方式:
1、使用try...catch...finally语句块处理它。
我们把这辆车可能出现的问题都考虑清楚了,
并提供了备选方案(出现问题怎么做),如果没有出现问题,那么用不到备选方案;
如果出现了问题,根据问题去找对应的备选方案,以保证车的正常运行;
如果出现了问题,但是又没备选方案,那么车就跑不了;
2、在函数签名中使用throws 声明交给函数调用者caller去解决。
我知道车可能又问题,但是我不处理,谁来使用了,告诉调用者,这里可能有问题;
那么调用者可以处理这个问题,也可以不处理;
如果它不处理,还是会出现问题,如果处理了,肯定没问题;
A -》 B -》 C
Java采用的异常处理机制,是将异常处理的程序代码集中在一起,与正常的程序代码分开,使得程序简洁、优雅,并易于维护。
Java提供的是异常处理的抓抛模型。
Java程序的执行过程中如出现异常,会生成一个异常类对象,该异常对象将被提交给Java运行时系统,这个过程称为抛出(throw)异常。
异常对象的生成:
由虚拟机自动生成:程序运行过程中,
虚拟机检测到程序发生了问题,如果在当前代码中没有找到相应的处理程序,
就会在后台自动创建一个对应异常类的实例对象并抛出——自动抛出。
由开发人员手动创建:
Exception exception = new ClassCastException();
创建好的异常对象不抛出对程序没有任何影响,和创建一个普通对象一样。
异常的抛出机制:
如果一个方法内抛出异常,该异常对象会被抛给调用者方法中处理。如果异常没有在调用者方法中处理,它继续被抛给这个调用方法的上层方法。这个过程将一直继续下去,直到异常被处理。这一过程称为捕获(catch)异常。
如果一个异常回到main()方法,并且main()也不处理,则程序运行终止。
程序员通常只能处理Exception,而对Error无能为力。
异常处理机制一:try-catch-finally
语法格式:
try{
...... //可能产生异常的代码
}
catch( ExceptionName1 e ){
...... //当产生ExceptionName1型异常时的处置措施
}
catch( ExceptionName2 e ){
...... //当产生ExceptionName2型异常时的处置措施
}
[ finally{
...... //无论是否发生异常,都无条件执行的语句
} ]
语法解释:
try:
捕获异常的第一步是用try{…}语句块选定捕获异常的范围,将可能出现异常的代码放在try语句块中。
如果发生异常,则尝试去匹配catch块,catch块可以有多个(因为try块可以出现多个不同类型异常);
如果执行完try不管有没有发生异常,则接着去执行finally块和finally后面的代码(如果有的话)。
catch (Exceptiontype e):
在catch语句块中是对异常对象进行处理的代码。每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常对象。
每一个catch块用于捕获并处理一个特定的异常,或者这异常类型的子类。Java可以将多个异常声明在一个catch中。 catch(Exception1 | Exception2 | Exception3 e)
catch后面的括号定义了异常类型和异常参数。如果异常与之匹配且是最先匹配到的,则虚拟机将使用这个catch块来处理异常。
在catch块中可以使用这个块的异常参数来获取异常的相关信息。异常参数是这个catch块中的局部变量,其它块不能访问。与其它对象一样,可以访问一个异常对象的成员变量或调用它的方法。
①、getMessage() 获取异常信息,返回字符串。
②、printStackTrace() 获取异常类名和异常信息,
以及异常出现在程序中的位置。返回值void。
如果当前try块中发生的异常在后续的所有catch中都没捕获到,则先去执行finally,然后到这个函数的外部caller中去匹配异常处理器。
如果try中没有发生异常,则所有的catch块将被忽略。
注意:如果明确知道产生的是何种异常,
可以用该异常类作为catch的参数;
也可以用其父类作为catch的参数。
比如:可以用 ArithmeticException 类作为参数的地方,
就可以用RuntimeException类作为参数,
或者用所有异常的父类Exception类作为参数。
但不能是与ArithmeticException类无关的异常,
如NullPointerException(catch中的语句将不会执行)。
finally:
finally块通常是可选的。捕获异常的最后一步是通过finally语句为异常处理提供一个统一的出口,使得在控制流转到程序的其它部分以前,能够对程序的状态作统一的管理。
不论在try代码块中是否发生了异常事件,catch语句是否执行,catch语句是否有异常,catch语句中是否有return,finally块中的语句都会被执行。
一个try至少要有一个catch块,否则, 至少要有1个finally块。但是finally不是用来处理异常的,finally不会捕获异常。
finally主要做一些清理工作,如流的关闭,数据库连接的关闭等。
public class Test_Input_01 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
/*
* 当我们只写一个try{}的时候,会报错:
* Syntax error, insert "Finally" to complete TryStatement
* 语法错误,插入“Finally”来完成Try块
*
* 总结: try不能单独存在,必须结合catch或finally来使用
* try块中没有异常,会执行finally(如果有)
* try块中有异常,会执行对应的catch块(如果有),try中异常发生点之后的代码将不会执行
*/
try{
//try块中放可能发生异常的代码。
//如果执行完try且不发生异常,则接着去执行finally块和finally后面的代码(如果有的话)。
//如果发生异常,则尝试去匹配catch块。异常点之后的代码不会运行
//这行代码有可能出错
int num1 = sc.nextInt(); //这行代码如果出现异常,那么后面的输出语句就不执行
int num2 = sc.nextInt();
System.out.println(num1+"\t"+num2);
System.out.println(num1/num2);
String str = null;
System.out.println(str.charAt(0));
}catch(InputMismatchException | NullPointerException e) {
// catch(异常对象) 当异常发生了,catch就会捕获对应的异常
// 每一个catch块用于捕获并处理一个特定的异常,或者这异常类型的子类。
//Java7中可以将多个异常声明在一个catch中。
// catch(Exception1 | Exception2 | Exception3 e)
// catch后面的括号定义了异常类型和异常参数。
//如果异常与之匹配且是最先匹配到的,则虚拟机将使用这个catch块来处理异常。
// 在catch块中可以使用这个块的异常参数来获取异常的相关信息。
//异常参数是这个catch块中的局部变量,其它块不能访问。
// 如果当前try块中发生的异常在后续的所有catch中都没捕获到,
//则先去执行finally,然后到这个函数的外部caller中去匹配异常处理器。
// 如果try中没有发生异常,则所有的catch块将被忽略。
System.out.println("catch块 - try里面发生了异常 - 空指针和输入不匹配异常都走这个Catch");
}catch(java.lang.ArithmeticException e){
e.getMessage();
System.out.println("算数异常:除数不能为0");
}catch(Exception e){
System.out.println("程序发生未知异常");
}finally {
// finally块通常是可选的。
// 无论异常是否发生,异常是否匹配被处理,finally都会执行。
// 一个try至少要有一个catch块,否则, 至少要有1个finally块。
//但是finally不是用来处理异常的,finally不会捕获异常。
// finally主要做一些清理工作,如流的关闭,数据库连接的关闭等。
System.out.println("finally块");
}
System.out.println("异常捕获之后的代码");
}
}
需要注意的地方
1、try块中的局部变量和catch块中的局部变量(包括异常变量),以及finally中的局部变量,他们之间不可共享使用。
2、每一个catch块用于处理一个异常。异常匹配是按照catch块的顺序从上往下寻找的,只有第一个匹配的catch会得到执行。匹配时,不仅运行精确匹配,也支持父类匹配,因此,如果同一个try块下的多个catch异常类型有父子关系,应该将子类异常放在前面,父类异常放在后面,这样保证每个catch块都有存在的意义。
3、java中,异常处理的任务就是将执行控制流从异常发生的地方转移到能够处理这种异常的地方去。也就是说:当一个函数的某条语句发生异常时,这条语句的后面的语句不会再执行,它失去了焦点。执行流跳转到最近的匹配的异常处理catch代码块去执行,异常被处理完后,执行流会接着在“处理了这个异常的catch代码块”后面接着执行。
有的编程语言当异常被处理后,控制流会恢复到异常抛出点接着执行,
这种策略叫做:resumption model of exception handling(恢复式异常处理模式)
而Java则是让执行流恢复到处理了异常的catch块后接着执行,
这种策略叫做:termination model of exception handling(终结式异常处理模式)
public static void main(String[] args){
try {
foo();
}catch(ArithmeticException ae) {
System.out.println("处理异常");
}
}
public static void foo(){
int a = 5/0; //异常抛出点
System.out.println("Look me!!!"); //不会执行
}
finally块不管异常是否发生,只要对应的try执行了,则它一定也执行。
只有一种方法让finally块不执行:System.exit()。
因此finally块通常用来做资源释放操作:关闭文件,关闭数据库连接等等。
良好的编程习惯是:在try块中打开资源,在finally块中清理释放这些资源。
需要注意的地方:
1、finally块没有处理异常的能力。处理异常的只能是catch块。
2、在同一try…catch…finally块中 ,如果try中抛出异常,且有匹配的catch块,则先执行catch块,再执行finally块。如果没有catch块匹配,则先执行finally,然后去外面的调用者中寻找合适的catch块。
3、在同一try…catch…finally块中 ,try发生异常,且匹配的catch块中处理异常时也抛出异常,那么后面的finally也会执行:首先执行finally块,然后去外围调用者中寻找合适的catch块。
这是正常的情况,但是也有特例。关于finally有很多恶心,偏、怪、难的问题.
具体在最后一节:finally块和return 讲解
不捕获异常时的情况:
前面使用的异常都是RuntimeException类或是它的子类,这些类的异常的特点是:即使没有使用try和catch捕获,Java自己也能捕获,并且编译通过( 但运行时会发生异常使得程序运行终止 )。
如果抛出的异常是IOException等类型的非运行时异常,则必须捕获,否则编译错误。也就是说,我们必须处理编译时异常,将异常进行捕捉,转化为运行时异常。
import java.io.*;
public class IOExp {
public static void main(String[] args) {
try {
FileInputStream in = new FileInputStream("hello.txt");
int b;
b = in.read();
while (b != -1) {
System.out.print((char) b);
b = in.read();
}
in.close();
} catch (IOException e) {
System.out.println(e);
} finally {
System.out.println(" It’s ok!");
}
}
}
异常处理机制二:throws
throws是另一种处理异常的方式,它不同于try…catch…finally,throws仅仅是将函数中可能出现的异常向调用者声明,而自己则不具体处理。
throws声明:如果一个方法内部的代码会抛出检查异常(checked exception),而方法自己又没有完全处理掉或并不能确定如何处理这种异常,则javac保证你必须在方法的签名上使用throws关键字声明这些可能抛出的异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理,否则编译不通过。
在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。
采取这种异常处理的原因可能是:方法本身不知道如何处理这样的异常,或者说让调用者处理更好,调用者需要为可能发生的异常负责。
语法格式:
修饰符 返回值类型 方法名() throws ExceptionType1 , ExceptionType2 ,ExceptionTypeN{
//方法内部可以抛出 ExceptionType1 , ExceptionType2 ,ExceptionTypeN 类的异常,或者他
们的子类的异常对象。
}
import java.io.*;
public class ThrowsTest {
public static void main(String[] args) {
ThrowsTest t = new ThrowsTest();
try {
t.readFile();
} catch (IOException e) {
e.printStackTrace();
}
}
public void readFile() throws IOException {
FileInputStream in = new FileInputStream("hello.txt");
int b;
b = in.read();
while (b != -1) {
System.out.print((char) b);
b = in.read();
}
in.close();
}
}
4.4手动抛出异常:throw
Java异常类对象除在程序执行过程中出现异常时由系统自动生成并抛出,也可根据需要使用人工创建并抛出。
首先要生成异常类对象,然后通过throw语句实现抛出操作(提交给Java运行环境)。
throw exceptionObject
程序员也可以通过throw语句手动显式的抛出一个异常。throw语句的后面可以抛出的异常必须是Throwable或其子类的实例。下面的语句在编译时将会产生语法错误:
throw new String(“你抛我试试.”);
throw 语句必须写在函数中,执行throw 语句的地方就是一个异常抛出点,它和由JRE自动形成的异常抛出点没有任何差别。
public class StudentTest {
public static void main(String[] args) {
try {
Student s = new Student();
s.regist(-1001);
System.out.println(s);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
class Student {
private int id;
public void regist(int id) throws Exception {
if (id > 0) {
this.id = id;
} else {
// System.out.println("您输入的数据非法!");
//手动抛出异常对象
// throw new RuntimeException("您输入的数据非法!");
throw new Exception("您输入的数据非法!");
//错误的
// throw new String("不能输入负数");
}
}
@Override
public String toString() {
return "Student [id=" + id + "]";
}
}
throws和throw的区别:
throw是语句抛出一个异常。
语法:throw (异常对象);
throw e;
throws是方法可能抛出异常的声明。(用在声明方法时,表示该方法可能要抛出异常)
语法:(修饰符)(方法名)([参数列表])[throws(异常类)]{…}
public void doA(int a) throws Exception1,Exception3{…}
throw语句用在方法体内,表示抛出异常,由方法体内的语句处理。
throws出现在方法函数头,表示在抛出异常,由该方法的调用者来处理。
throws主要是声明这个方法会抛出这种类型的异常,使它的调用者知道要捕获这个异常。
throw是具体向外抛异常的动作,所以它是抛出一个异常实例。
throws说明你有那个可能,倾向。
throw的话,那就是你把那个倾向变成真实的了。
两者都是消极处理异常的方式(这里的消极并不是说这种方式不好),只是抛出或者可能抛出异常,但是不会由函数去处理异常,真正的处理异常由函数的上层调用处理。
原文链接:链接描述
5.理解OOP面向对象
面向对象有哪些特性?
封装,继承,多态
1、封装就是将类的信息隐藏在类内部,不允许外部程序直接访问,而是通过该类的方法实现对隐藏信息的操作和访问。 良好的封装能够减少耦合。
2、继承是从已有的类中派生出新的类,新的类继承父类的属性和行为,并能扩展新的能力,大大增加程序的重用性和易维护性。在Java中是单继承的,也就是说一个子类只有一个父类。
3、多态是同一个行为具有多个不同表现形式的能力。在不修改程序代码的情况下改变程序运行时绑定的代码。实现多态的三要素:继承、重写、父类引用指向子类对象。
静态多态性:通过重载实现,相同的方法有不同的參数列表,可以根据参数的不同,做出不同的处理。
动态多态性:在子类中重写父类的方法。运行期间判断所引用对象的实际类型,根据其实际类型调用相应的方法。
6.Java的特点
Java是一门面向对象的编程语言。
Java具有平台独立性和移植性。
Java有一句口号:Write once, run anywhere,一次编写、到处运行。这也是Java的魅力所在。而实现这种特性的正是Java虚拟机JVM。已编译的Java程序可以在任何带有JVM的平台上运行。你可以在windows平台编写代码,然后拿到linux上运行。只要你在编写完代码后,将代码编译成.class文件,再把class文件打成Java包,这个jar包就可以在不同的平台上运行了。
Java具有稳健性。
Java是一个强类型语言,它允许扩展编译时检查潜在类型不匹配问题的功能。Java要求显式的方法声明,它不支持C风格的隐式声明。这些严格的要求保证编译程序能捕捉调用错误,这就导致更可靠的程序。
异常处理是Java中使得程序更稳健的另一个特征。异常是某种类似于错误的异常条件出现的信号。使用try/catch/finally语句,程序员可以找到出错的处理代码,这就简化了出错处理和恢复的任务。
Java是如何实现跨平台的?
Java是通过JVM(Java虚拟机)实现跨平台的。
JVM可以理解成一个软件,不同的平台有不同的版本。我们编写的Java代码,编译后会生成.class 文件(字节码文件)。Java虚拟机就是负责将字节码文件翻译成特定平台下的机器码,通过JVM翻译成机器码之后才能运行。不同平台下编译生成的字节码是一样的,但是由JVM翻译成的机器码却不一样。
只要在不同平台上安装对应的JVM,就可以运行字节码文件,运行我们编写的Java程序。
因此,运行Java程序必须有JVM的支持,因为编译的结果不是机器码,必须要经过JVM的翻译才能执行。
Java 与 C++ 的区别
Java 是纯粹的面向对象语言,所有的对象都继承自 java.lang.Object,
C++ 兼容 C ,不但支持面向对象也支持面向过程。
Java 通过虚拟机从而实现跨平台特性, C++ 依赖于特定的平台。
Java 没有指针,它的引用可以理解为安全指针,而 C++ 具有和 C 一样的指针。
Java 支持自动垃圾回收,而 C++ 需要手动回收。
Java 不支持多重继承,只能通过实现多个接口来达到相同目的,而 C++ 支持多重继承。
7.JDK/JRE/JVM三者的关系
JVM
英文名称(Java Virtual Machine),就是我们耳熟能详的 Java 虚拟机。Java 能够跨平台运行的核心在于 JVM 。
所有的java程序会首先被编译为.class的类文件,这种类文件可以在虚拟机上执行。也就是说class文件并不直接与机器的操作系统交互,而是经过虚拟机间接与操作系统交互,由虚拟机将程序解释给本地系统执行。
针对不同的系统有不同的 jvm 实现,有 Linux 版本的 jvm 实现,也有Windows 版本的 jvm 实现,但是同一段代码在编译后的字节码是一样的。这就是Java能够跨平台,实现一次编写,多处运行的原因所在。
JRE
英文名称(Java Runtime Environment),就是Java 运行时环境。我们编写的Java程序必须要在JRE才能运行。它主要包含两个部分,JVM 和 Java 核心类库。
JRE是Java的运行环境,并不是一个开发环境,所以没有包含任何开发工具,如编译器和调试器等。
如果你只是想运行Java程序,而不是开发Java程序的话,那么你只需要安装JRE即可。
JDK
英文名称(Java Development Kit),就是 Java 开发工具包
学过Java的同学,都应该安装过JDK。当我们安装完JDK之后,目录结构是这样的
可以看到,JDK目录下有个JRE,也就是JDK中已经集成了 JRE,不用单独安装JRE。
另外,JDK中还有一些好用的工具,如jinfo,jps,jstack等。
最后,总结一下JDK/JRE/JVM,他们三者的关系
JRE = JVM + Java 核心类库
JDK = JRE + Java工具 + 编译器 + 调试器
8.面向对象和面向过程的区别?
面向对象和面向过程是一种软件开发思想。
面向过程就是分析出解决问题所需要的步骤,然后用函数按这些步骤实现,使用的时候依次调用就可以了。
面向对象是把构成问题事务分解成各个对象,分别设计这些对象,然后将他们组装成有完整功能的系统。
面向过程只用函数实现,面向对象是用类实现各个功能模块。
9.八大数据类型
整数:byte ,short,int ,long
小数:float,double
字符:char
布尔型:boolean
byte,8bit
char,16bit
short,16bit
int,32bit
float,32bit
long,64bit
double,64bit
boolean,只有两个值:true、false,可以使⽤用 1 bit 来存储
为什么不能用浮点型表示金额?
由于计算机中保存的小数其实是十进制的小数的近似值,并不是准确值,所以,千万不要在代码中使用浮点数来表示金额等重要的指标。
建议使用BigDecimal或者Long来表示金额。
10.什么是值传递和引用传递?
值传递是对基本型变量而言的,传递的是该变量的一个副本,改变副本不影响原变量。
引用传递一般是对于对象型变量而言的,传递的是该对象地址的一个副本,并不是原对象本身,两者指向同一片内存空间。所以对引用对象进行操作会同时改变原对象。
java中不存在引用传递,只有值传递。即不存在变量a指向变量b,变量b指向对象的这种情况。