面试 —— Java基础
final
作用final
、finally
、finalize
区别this
和super
的区别- 抽象类和接口的区别
- 普通类和抽象类有哪些区别?
- 抽象类能使用final修饰么?
- 创建一个对象用什么关键字?对象实例和对象引用有何不同?
- 成员变量和局部变量的区别
- 在Java中定义一个不做事切没有参数的构造方法的作用
- 在调用子类构造方法之前会先调用父类没有参数的构造方法,其目的是?
- 一个类的构造方法的作用是什么?若一个类没有声明构造方法,改程序能正确执行吗?为什么?
- 构造方法有哪些特征?
- 静态变量和实例变量的区别
- 静态变量与普通变量区别
- 内部类的有点
- 局部内部类和匿名内部类访问局部变量的时候,为什么变量必须要加上final?
- 构造器(constructor)是否可以被重写(override)?
- 重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分?
- == 和 equals的区别
final
作用
用于修饰类、属性和方法。
- 被
final
修饰的类不可以被继承。 - 被
final
修饰的方法不可以被重写。 - 被
final
修饰的变量不可以被改变,被final
修饰不可变的是变量的引用,而不是引用指向的内容,引用指的内容是可以改变的。
final
、finally
、finalize
区别
-
final
可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量表示该变量是一个常量不能被重新赋值。 -
finally
一般作用在try-catch
代码块中,在处理异常的时候,通常我们将一定要执行的代码方法finally代码块中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码。 -
finalize
是一个方法,属于Object
类的一个方法,而Object
类是所有类的父类,该方法一般由垃圾回收器来调用,当我们调用System.gc()
方法的时候,由垃圾回收器调用finalize()
,回收垃圾,一个对象是否可回收的最后判断.
this
和 super
的区别
super
:它引用当前对象的直接父类中的成员(用来访问直接父类中被隐藏的父类中成员数据或函数,基类与派生类中有相同成员定义时如:super.变量名 super.成员函数据名(实参)this
:- 它代表当前对象名(在程序中易产生二义性之处,应使用this来指明当前对象;如果函数的形参与类中的成员数据同名,这时需用this来指明成员变量名)
super()
和this()
类似,区别是:super()
在子类中调用父类的构造方法,this()
在本类中调用本类的其它构造方法。super()
和this()
均需放在构造方法内第一行。尽管可以用this
调用一个构造器,但却不能调用两个。this
和super
不能同时出现在一个构造函数里面,因为this
必然会调用其它的构造函数,其它的构造函数必然也会有super
语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。this()
和super()
都指的是对象,所以,均不可以在static
环境中使用。包括:static
变量,static
方法,static
语句块。- 从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。
抽象类和接口的区别
抽象类是用来捕捉子类的通用特性的。接口是抽象方法的集合。
从设计层面上来说,抽象类是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范。
相同点:
- 接口和抽象类都不能实例化
- 都位于继承的顶端,用于被其他实现或继承
- 都包含抽象的方法,其子类都必须覆盖这些抽象方法
不同点:
参数 | 抽象类 | 接口 |
---|---|---|
声明 | 抽象类使用abstract 关键字来声明 |
接口使用interface 关键字声明 |
实现 | 子类使用extend 关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有生命的方法的实现 |
子类使用implements 关键字来实现接口。它需要提供接口中所有声明方法的实现 |
构造器 | 抽象类可以有构造器 | 接口不能有构造器 |
访问修饰符 | 抽象类中的方法可以是任意访问修饰符 | 接口方法默认修饰符是public ,并且不允许定义为private 或者protected |
多继承 | 一个类最多只能继承一个抽象类 | 一个类可以实现多个接口 |
字段声明 | 抽象类的字段声明可以是任意的 | 接口的字段默认都是static 和final |
Java8中接口中引入默认方法和静态方法,以此来减少抽象类和接口之间的差异。现在,我们可以为接口提供默认实现的方法了,并且不用强制子类来实现它。
接口和抽象类各有优缺点,在接口和抽象类的选择上,必须遵守这样一个原则:
- 行为模型应该总是通过接口而不是抽象类定义,所以通常是优先选用接口,尽量少用抽象类。
- 选择抽象类的时候通常是如下情况:需要定义子类的行为,又要为子类提供通用的功能。
普通类和抽象类有哪些区别?
- 普通类不能包含抽象方法,抽象类可以包含抽象方法。
- 抽象类不能直接实例化,普通类可以直接实例化。
抽象类能使用final修饰么?
不能,定义抽象类就是让其他类继承Dee,如果定义为final该类就不能被继承。
创建一个对象用什么关键字?对象实例和对象引用有何不同?
new关键字,new创建对象实例(对象实例在堆内存中),对象引用指向对象实例(对象引用存放在栈内存中)。一个对象引用可以指向0个或1个对象(一根绳子可以不系绳子,也可以系一个气球);一个对象可以有n个引用指向他。
成员变量和局部变量的区别
- 变量:在程序执行的过程中,在某个范围内其值可以发生改变的量。从本质上讲,变量其实是内存中的一小块区域。
- 成员变量:方法外部,类内部定义的变量
- 局部变量:类的方法中的变量
存储位置:
- 成员变量:随着对象的创建而存在,随着对象的消失而消失,存储在堆内存中
- 局部变量:在方法被调用,或者语句被执行的时候存在,存储在栈内存中。当方法调用完,或者语句结束后,就自动释放。
生命周期:
- 成员变量:随着对象的创建而存在,随着对象的消失而消失
- 局部变量:当方法调用完,或者语句结束,就自动释放
初始值:
- 成员变量:没有默认初始值
- 局部变量:没有默认初始值,但在使用前必须赋值
使用原则:
- 在使用变量时需要遵循就近原则
- 首先在局部范围查找,有就使用,接着再成员位置找。
在Java中定义一个不做事切没有参数的构造方法的作用
Java程序在执行子类的构造方法之前,如果没有用super()来调用父类特定的构造方法,则会调用父类中
“没有参数的构造方法”。因此,如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有
用super()来调用父类中特定的构造方法,则编译时将发生错误,因为Java程序在父类中找不到没有参数
的构造方法可供执行。解决办法是在父类里加上一个不做事且没有参数的构造方法。
在调用子类构造方法之前会先调用父类没有参数的构造方法,其目的是?
帮助子类做初始化工作
一个类的构造方法的作用是什么?若一个类没有声明构造方法,改程序能正确执行吗?为什么?
主要作用是完成对象的初始化工作,可以执行,因为一个类即使没有声明构造方法也会有默认的不带参的构造器。
构造方法有哪些特征?
名字与类名相同
没有返回值,但不能用void声明构造函数
生成类的对象时自动执行,无需调用
静态变量和实例变量的区别
静态变量: 静态变量由于不属于任何实例对象,属于类的,所以在内存中只会有一份,在类的加载过程
中,JVM只为静态变量分配一次内存空间。
实例变量: 每次创建对象,都会为每个对象分配成员变量内存空间,实例变量是属于实例对象的,在内
存中,创建几次对象,就有几份成员变量。
静态变量与普通变量区别
static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中
只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的
时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
还有一点就是static成员变量的初始化顺序按照定义的顺序进行初始化。
内部类的有点
- 一个内部类对象可以访问创建它的外部类的对象,包括私有数据
- 内部类不为同一包的其他类所见,具有很好的封装性
- 内部类有效实现了多重继承,优化java单继承的缺陷
- 匿名内部类可以很方便的定义回调
局部内部类和匿名内部类访问局部变量的时候,为什么变量必须要加上final?
生命周期不一致, 局部变量直接存储在栈中,当方法执行结束后,非final的局部变量就被销毁。而局部内部类对局部变量的引用依然存在,如果局部内部类要调用局部变量时,就会出错。加了final,可以确保局部内部类使用的变量与外层的局部变量区分开,解决了这个问题。
构造器(constructor)是否可以被重写(override)?
构造器不能被继承,因此不能被重写,但是可以被重载
重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分?
方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行
时的多态性。
重载:发生在同一个类中,方法名相同参数列表不同(参数类型不同、个数不同、顺序不同),与方法
返回值和访问修饰符无关,即重载的方法不能根据返回类型进行区分
重写:发生在父子类中,方法名、参数列表必须相同,返回值小于等于父类,抛出的异常小于等于父
类,访问修饰符大于等于父类(里氏代换原则);如果父类方法访问修饰符为private则子类中就不是重
写。
== 和 equals的区别
==
:- 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。(基本数据类型
== 比较的是值,引用数据类型 == 比较的是内存地址) equals()
:它的作用也是判断两个对象是否相等。但它一般有两种使用情况:- 类没有覆盖
equals()
方法,则通过equals()
比较该类的两个对象时,等价于通过==
- 类覆盖了
equals()
方法。 - 一般,我们都覆盖 equals() 方法来两个对象的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。
- 类没有覆盖
- String中的equals方法是被重写过的,因为object的equals方法是比较的对象的内存地址,而String的equals方法比较的是对象的值。
- 当创建String类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个String对象。