文章目录
- 01. 面向对象的思想在Java中如何体现?
- 02. 面向对象的3大特征是什么?
- 03. final关键字的作用?
- 04. 访问修饰符public,private,protected,以及不写(默认)时的区别?
- 05. 普通类和抽象类有哪些区别?
- 06. 接口和抽象类有什么区别?
- 07. 方法重载和重写的区别?
- 08. 静态方法和静态变量的目的是什么?
- 09. 阐述静态变量和实例变量的区别?
- 10. 是否可以从一个静态方法内部发出对非静态方法的调用?
- 11. static关键字如何使用?
- 12. static修饰的方法是否可以被继承和重写?
- 13. 抽象方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被synchronized修饰?
- 14. 构造器是否可被重写?
- 15. 接口是否可继承接口?抽象类是否可实现接口?抽象类是否可继承具体类?
- 16. super关键字的作用?
- 17. 什么是继承?
- 18. 谈谈你对多态的理解?
- 19. 实现多态的3个条件是什么?
- 20. 包装类
- 21. 自动装箱和拆箱
- 22. int和Integer的区别?
01. 面向对象的思想在Java中如何体现?
答:通过类和对象,在程序中使用对象来描述具体的事物,当多个事物具有共同的特点时,可以将事物的共同特点进行抽象,然后封装成一个包含事物共同特点的类。
02. 面向对象的3大特征是什么?
答:面向对象的主要特点是:封装(抽象)、继承和多态。
(1) 封装(抽象)
所谓抽象,就是将一些具体的事物之间存在的共同之处抽取出来,然后形象化的描述,在java中抽象的过程就是将事物共同的静态属性和动态属性封装成类的过程,事物的静态属性可以抽象成变量,动态属性则可以封装成一个方法(函数),封装是面向对象的核心思想,封装指的的是将对象的属性和动作进行封装,对外隐藏本身的实现细节。例如:狗、猫,可以找他们之间的共同点,都有颜色这一属性,则可以封装一个颜色属性到类中;再者他们都要吃饭,则可以封装一个吃饭的方法到类中,不管是狗还是猫,我们只需要知道他们能吃饭就可以了,并不需要具体了解他们吃饭的具体步骤,这就是对外开放但是隐藏本身的实现细节。
(2) 继承
当一个类被封装后,一般不鼓励二次封装,一般当类的功能不足以支持当前需求时,我们会考虑对此类进行扩展,java中可以使用继承来实现这一想法。每一个类只能继承一个父类,所以java中是单继承。
(3) 抽象类和接口
如果声明了一个方法,但是不知如何实现,这时可以将方法体删掉,然后使用修饰符abstract 来修饰这个方法,这个方法就叫做抽象方法,如果一个类中存在抽象方法,那么这个类必须使用abstract修饰,以将此类标记成抽象类,如果一个类中的所有方法都是抽象的,那么这个类就可以声明成一个接口,使用interface 来声明接口。抽象类和接口都不可以实例化(就是指不可以使用new关键字来创建对象)。抽象类可以被继承,如果子类声明的不是抽象类,那么就必须重写继承的抽象父类中的所有抽象方法。接口可以被实现,使用implements 关键字进行接口的实现,实现接口的类如果不声明成抽象类,就必须重写实现接口中所有的方法,一个类不可以继承多个类,但是可以实现多个接口,这样就解决的java单继承的尴尬。
(4) 多态
多态就是多种状态,同一类的不同对象所表现的不同的状态,就是父类(接口)的引用指向子类(实现类)的对象,实现多态有以下几中方式 :继承类、实现接口。例如封装一个动物类,类中有动物的颜色属性、动物吃饭方法,然后分别封装狗类和猫类都继承动物类,声明一个动物类的变量指向一个狗的对象,这时动物就表现出了多态性,创建谁的对象,这个动物就会表现出谁的状态。
Java引用变量有两个类型:一个是编译时类型,一个是运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。如果编译时类型和运行时类型不一致,就可能出现所谓的多态。多态靠的是父类或接口中定义的引用变量指向子类或具体实现类的实例对象,程序调用的方法在编程时并不确定,而是在程序运行期间才确定,即一个引用变量指向哪个类的实例对象,就调用哪个类中实现的方法。
03. final关键字的作用?
答:final可用来修饰类、方法、变量,被修饰的类不可被继承、被修饰的方法不能重写、被修饰的变量不能重新赋值。只需记住一点,只要被final修饰,什么东西就都不能改了,保持最终的状态。
04. 访问修饰符public,private,protected,以及不写(默认)时的区别?
修饰符 | 当前类 | 同 包 | 子 类 | 其他包 |
---|---|---|---|---|
public | √ | √ | √ | √ |
protected | √ | √ | √ | × |
default | √ | √ | × | × |
private | √ | × | × | × |
类的成员不写访问修饰时默认为default。默认对于同一个包中的其他类相当于公开(public),对于不是同一个包中的其他类相当于私有(private)。受保护(protected)对子类相当于公开,对不是同一包中的没有父子关系的类相当于私有。Java中,外部类的修饰符只能是public或默认,类的成员(包括内部类)的修饰符可以是以上四种
05. 普通类和抽象类有哪些区别?
(1) 抽象类的存在时为了被继承,不能实例化;
(2) 抽象类可以有抽象方法,只需申明,无须实现;
(3) 有抽象方法的类一定是抽象类;
(4) 抽象类的子类必须实现抽象类中的所有抽象方法,否则子类仍然是抽象类;
(5) 抽象方法不能声明为静态、不能被static、final修饰;
(6) 可以声明一个类没有任何抽象方法;
06. 接口和抽象类有什么区别?
答:抽象类和接口都不能够实例化,但可以定义抽象类和接口类型的引用。一个类如果继承了某个抽象类或者实现了某个接口都需要对其中的抽象方法全部进行实现,否则该类仍然需要被声明为抽象类。接口比抽象类更加抽象,因为抽象类中可以定义构造器,可以有抽象方法和具体方法,而接口中不能定义构造器而且其中的方法全部都是抽象方法。抽象类中的成员可以是private、默认、protected、public的,而接口中的成员全都是public的。抽象类中可以定义成员变量,而接口中定义的成员变量实际上都是常量。有抽象方法的类必须被声明为抽象类,而抽象类未必要有抽象方法。
java8之前,接口中的方法都是抽象方法,省略了public abstract。
java8之后,接口中可以定义静态方法,静态方法必须有方法体,普通方法没有方法体,需要被实现;
(1) 接口使用interface修饰;
(2) 接口不能实例化;
(3) 一个类可以实现多个接口;
抽象类中可以包含抽象方法和非抽象方法,非抽象方法需要有方法体;
(1) 抽象类使用abstract修饰;
(2) 抽象类不能被实例化;
(3) 抽象类只能单继承;
07. 方法重载和重写的区别?
方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。
重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载,与方法返回值类型无关,所以不能根据返回值类型区分方法是否重载,因为重载是编译时多态,调用时不能指定类型信息,所以编译器不知道要调用的是哪个方法;
比如:当调用max(1,2)时,可能你自己都不知道要调用的是哪个方法,编译器更不会知道,所以返回值类型不同的重载是不被允许的。
float max(int a,int b);
int max(int a,int b);
重写发生在父类和子类之间,子类继承父类方法(非构造、final、static修饰的方法)并重写父类方法,要求子类重写方法的参数列表、返回值类型必须和父类被重写的方法保持一致,访问权限不能低于父类被重写的方法,不能比父类被重写方法声明更多的异常。
08. 静态方法和静态变量的目的是什么?
答:静态变量被类的所有实例共用,静态类只能访问类的静态变量,或调用类的静态方法。
static可以修饰变量、方法、代码块,只需要记住一点:被static修饰的属性和方法是所有根据当前类创建的对象所共享的,一个对象做出修改,其他对象就会修改,在内存中只有一份。
09. 阐述静态变量和实例变量的区别?
答:静态变量是被static修饰符修饰的变量,也称为类变量,它属于类,不属于类的任何一个对象,一个类不管创建多少个对象,静态变量在内存中有且仅有一个拷贝;实例变量必须依存于某一实例,需要先创建对象然后通过对象才能访问到它。静态变量可以实现让多个对象共享内存。
10. 是否可以从一个静态方法内部发出对非静态方法的调用?
答:不可以,静态方法只能访问静态成员,因为非静态方法的调用要先创建对象,在调用静态方法时可能对象并没有被初始化。
11. static关键字如何使用?
(1) static 是一个修饰符,它表示静态的意思,它可以修饰属性、方法、代码块 ,但不能修饰构造方法和外部类;
(2) static修饰的属性属于类而不属于某个对象(static修饰的属性,不管类中new多少个对象,static属性是所有对象共用的),static修饰的方法中不能以任何的形式访问this和super;
(3) 类中的静态成员内存只分配一次,在类装载器中完成。如果想第一时间执行加载的代码可以放在静态代码块中执行,不管调用这个类多少次,静态代码块只执行一次;
(4) 静态方法内:可以访问静态成员,因为它在类装载器中已经开辟好了内存;
(5) 非静态方法内:可以访问静态成员;
(6) 静态方法内:不可以访问非静态成员。如果想要调用就必须要new对象,通过对象名.方法名或对象名.属性名调用,因为非静态方法和非静态属性在new对象的时候才开辟内存;
(7) 调非本类中的静态成员可以通过类名和对象名调用;
public class A {
private int age;
private static String name;
public void show(){
System.out.println("show。。。。");
}
public static void show1(){
System.out.println("show static。。。。");
}
// 静态方法内:可以访问静态方法
public static void test5(){
show1();
}
// 静态方法内:可以访问静态变量
public static void test6(){
System.out.println(name);
}
// 非静态方法内:可以访问静态变量
public void test1(){
System.out.println(name);
}
// 非静态方法内:可以访问静态方法
public void test2(){
show1();
}
// 静态方法内:无法访问非静态方法,编译错误
public static void test3(){
//
// show();
new A().show();
}
// 静态方法内:无法访问非静态变量,编译错误
public static void test4(){
// System.out.println(age);
System.out.println(new A().age);
}
}
// 调非本类中的静态成员可以通过类名和对象调,但是java不推荐用对象调用static方法
public class B extends A {
public void test(){
A.show1();
}
public static void main(String[] args) {
A a = new A();
a.show1();
}
}
12. static修饰的方法是否可以被继承和重写?
答:子类会继承父类的静态方法和静态变量,但是无法对静态方法进行重写,但是不支持多态。
子类可以拥有和父类同名的,同参数的静态方法,但是这并不是对父类静态方法的重写,是子类自己的静态方法,子类只是把父类的静态方法隐藏了。
当父类的引用指向子类时,使用对象调用静态方法或者静态变量,是调用的父类中的静态方法或者变量,无法形成多态。
public class A {
static String name="zhangsan";
static int age=5;
public static void show(){
System.out.println("A show....");
}
}
// 子类可以继承父类的静态成员:方法和变量
public class B extends A {
public static void main(String[] args) {
B.show(); //A show....
System.out.println(B.name);// zhangsan
}
}
// 子类可以拥有和父类同名的,同参数的静态方法,但是这并不是对父类静态方法的重写,是子类自己的静态方法
public class B extends A {
public static void show(){
System.out.println("B show....");
}
public static void main(String[] args) {
B.show(); // B show....
}
}
// 当父类的引用指向子类时,使用对象调用静态方法或者静态变量,是调用的父类中的静态方法或者变量,无法形成多态
public class B extends A {
public static void show(){
System.out.println("B show....");
}
public static void main(String[] args) {
A a = new B();
a.show(); // A show....
}
}
13. 抽象方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被synchronized修饰?
答:都不能。抽象方法需要子类重写,而静态的方法是无法被重写的,因此二者是矛盾的。本地方法是由本地代码(如C代码)实现的方法,而抽象方法是没有实现的,也是矛盾的。synchronized和方法的实现细节有关,抽象方法不涉及实现细节,因此也是相互矛盾的。
14. 构造器是否可被重写?
答:构造器不能被继承,因此不能被重写,但可以被重载。
15. 接口是否可继承接口?抽象类是否可实现接口?抽象类是否可继承具体类?
答:接口可以继承接口,而且支持多重继承。抽象类可以实现(implements)接口,抽象类可继承具体类也可以继承抽象类。
16. super关键字的作用?
super 关键字主要应用于继承关系实现子类对父类方法的调用,包括对父类构造方法和一般方法的调用。
(1) 子类不能继承父类的构造方法:如果基类中没有默认构造方法或希望调用带参数的基类构造方法,要使用关键字 super 来显示调用基类构造方法。使用关键字 super 调用基类构造方法的语句,必须是子类构造方法的第一个可执行语句。调用基类构造方法时,传递的参数不能是关键字 this 或当前对象的非静态成员。
(2) 在 Java 中,有时还会遇到子类中的成员变量或方法与父类中的成员变量或方法同名。同名子类中的成员变量或方法名优先级高,所以子类中的同名成员变量或方法覆盖了父类的成员变量或方法,但是我们如果想要使用父类中的这个成员变量或方法,就需要用到 super 。
(3) 可以用 super 直接传递参数。
public class Person {
Person(){
prt("A Person.");
}
Person(String name){
prt("A person name is:" + name);
}
public static void prt(String s){
System.out.println(s);
}
}
public class Chinese extends Person {
Chinese(){
super(); //调用父类无形参构造方法
prt("A chinese"); //调用父类的方法prt
}
Chinese(String name){
super(name); //调用父类具有相同形参的构造方法
prt("his name is:" + name);
}
Chinese(String name,int age){
this(name); //调用当前具有相同形参的构造方法
prt("his age is:" + age);
}
public static void main(String[] args) {
Chinese cn = new Chinese();
cn = new Chinese("Kevin");
cn = new Chinese("Jhone",21);
}
}
17. 什么是继承?
答:子类自动继承父类的属性和方法,子类中不再存在重复代码,从而实现代码的重用。
(1) 子类继承父类所有的成员变量和成员方法,但不能继承父类的构造方法。在子类的构造方法中,可使用语句super关键字调用父类的构造方法。
(2) 子类继承父类中被声明为 public 和 protected 的成员变量和成员方法,但是不能继承被声明为 private 的成员变量和成员方法。
(3) 重写父类成员,包括数据成员和成员函数。如果子类声明了一个与父类成员函数相同的成员函数,子类中的新成员则屏蔽了父类同名成员,类似函数中的局部变量屏蔽了全局变量,称为同名覆盖。
(4) 定义新成员,新成员是派生类自己的新特性。派生类新成员的加入使得派生类在功能上有所发展。
(5) 必须在派类中重写构造方法,因为构造方法不能继承。
18. 谈谈你对多态的理解?
多态是指在父类中定义的属性和方法被子类继承之后,可以具有不同的数据类型或表现出不同的行为,这使得同一个属性或方法在父类及其各个子类中具有不同的含义。
对面向对象来说,多态分为编译时多态和运行时多态。其中编译时多态是静态的,主要是指方法的重载,它是根据参数列表的不同来区分不同的方法。通过编译之后会变成两个不同的方法,在运行时谈不上多态。而运行时多态是动态的,它是通过动态绑定来实现的,也就是大家通常所说的多态性。
19. 实现多态的3个条件是什么?
Java 实现多态有 3 个必要条件:继承、重写和向上转型。只有满足这 3 个条件,开发人员才能够在同一个继承结构中使用统一的逻辑实现代码处理不同的对象,从而执行不同的行为。
(1) 继承:在多态中必须存在有继承关系的子类和父类。
(2) 重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
(3) 向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才既能可以调用父类的方法,又能调用子类的方法。
20. 包装类
Java语言是一个面向对象的语言,但是Java中的基本数据类型却是不面向对象的。基本类型的数据不具备"对象"的特性(没有成员变量和成员方法可以调用),因此,java为每种数据类型分别设计了对应的类,即包装类。
(1) 所有包装类都是final类型,因此不能创建他们的子类。
(2) 包装类是不可变类,一个包装类的对象自创建后,他所包含的基本类型数据就不能被改变。
基本数据类型 | 对应的包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
char | Character |
floar | Float |
double | Double |
boolean | Boolean |
21. 自动装箱和拆箱
装箱:将基本数据类型变为包装类对象。
拆箱:将包装类中包装的基本数据类型取出。
int到Integer类的3种方法:
(1)使用Integer类的构造方法
(2)使用Integer类内部的valueOf( )方法
(3)自动装箱
// 使用Integer类的构造方法
Integer i1 = new Integer(i);
// 使用Integer类内部的valueOf( )方法
Integer i2 = Integer.valueOf(30);
// 自动装箱
Integer i3 = 100; //编译器自动执行了Integer ii = Integer.valueOf(100)
valueOf源码分析:
public static Integer valueOf(int i) {
assert IntegerCache.high>= 127;
if (i >= IntegerCache.low&& i <= IntegerCache.high)
return IntegerCache.cache[i+ (-IntegerCache.low)];
return new Integer(i);
}
通过查看原码可知,java针对-128-127之间的数据做了一个数据缓冲池。
如果数据是该范围内的,每次并不创建新的空间。如果数据是该范围内的,就new一个空间。
Integer类到 int的2种方法:
(1)调用包装类的intValue()方法
(2)通过自动拆箱
// 1.调用包装类的XxxValue()方法
Integer i1 = new Integer(14);
int i2 = i1.intValue();
// 2.自动拆箱,实际上执行了 int i2 = i1.intValue()
int i2=i1;
22. int和Integer的区别?
两者的区别主要体现在以下几个方面:
(1) 数据类型不同:int 是基础数据类型,而 Integer 是包装数据类型;
(2) 默认值不同:int 的默认值是 0,而 Integer 的默认值是 null;
(3) 内存中存储的方式不同:int 在内存中直接存储的是数据值,而 Integer 实际存储的是对象引用,当 new 一个 Integer 时实际上是生成一个指针指向此对象;
(4) 实例化方式不同:Integer 必须实例化才可以使用,而 int 不需要;
(5) 变量的比较方式不同:int 可以使用 == 来对比两个变量是否相等,而 Integer 一定要使用 equals 来比较两个变量是否相等。
public class B {
public static void main(String[] args) {
Integer a = 100;
Integer b = 100;
Integer c = 128;
Integer d = 128;
Integer e = new Integer(100);
Integer f = new Integer(100);
Integer h = 100;
int g = new Integer(100);
System.out.println(a==b); // true
System.out.println(c==d); // false
System.out.println(e==f); // false
System.out.println(a==e); // false
System.out.println(e==g); // true
System.out.println(a==f); // false
}
}