1. 面向对象的三大基本特征
封装性:所谓封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。在一个对象内部,某些代码或某些数据可以是私有的,不能被外界访问。
继承性:它可以使用现有类的所有功能,并在无需重新编写原来类的情况下对这些功能进行扩展。这种派生方式提现了传递性。通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。
多态性:多态就是指一个类实例的相同方法在不同情形有不同表现形式。多态机制使具有不同内部结构的对象可以共享相同的外部接口。
2. 面向对象的五大基本原则
单一职责原则(Single-Responsibility Principle)
核心思想为:一个类,最好只做一件事,只有一个引起它的变化。单一职责原则可以看做是低耦合、高内聚在面向对象原则上的引申
开放封闭原则(Open-Closed principle)
核心思想是:软件实体应该是可扩展的,而不可修改的。也就是,对扩展开放,对修改封闭的。实现开放封闭原则的核心思想就是对抽象编程,而不对具体编程,因为抽象相对稳定。
Liskov替换原则(Liskov-Substitution Principle)
依赖倒置原则(Dependecy-Inversion Principle)
接口隔离原则(Interface-Segregation Principle)
3. 什么是多态?
概念:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。(运行期状态)
必要条件:
为了实现运行期的多态,或者说是动态绑定,需要满足三个条件:
-
有类继承或者接口实现
-
子类要重写父类的方法
-
父类的引用指向子类的对象
举例如下:(帮助理解)
public class Parent{
public void call(){
sout("im Parent");
}
}
public class Son extends Parent{// 1.有类继承或者接口实现
public void call(){// 2.子类要重写父类的方法
sout("im Son");
}
}
public class Daughter extends Parent{// 1.有类继承或者接口实现
public void call(){// 2.子类要重写父类的方法
sout("im Daughter");
}
}
public class Test{
public static void main(String[] args){
Parent p = new Son(); //3.父类的引用指向子类的对象
Parent p1 = new Daughter(); //3.父类的引用指向子类的对象
}
}
4. 方法重写与重载
a.定义:
重写:是在Java的子类与父类中有两个名称、参数列表都相同的方法的情况。由于他们具有相同的方法签名,所以子类中的该方法将覆盖父类中原有的方法。(重写是多态性的体现)
重载:是函数或者方法有同样的名称,但是参数列表不相同的情形,这样的同名不同参数的函数或者方法之间,互相称之为重载函数或者方法。
b. 区别:
1、重载是一个编译期概念、重写是一个运行期间概念。
2、重载遵循所谓“编译期绑定”,即在编译时根据参数变量的类型判断应该调用哪个方法。
3、重写遵循所谓“运行期绑定”,即在运行的时候,根据引用变量所指向的实际对象的类型来调用方法
4、因为在编译期已经确定调用哪个方法,所以重载并不是多态。而重写是多态。重载只是一种语言特性,是一种语法规则,与多态无关,与面向对象也无关。(注:严格来说,重载是编译时多态,即静态多态。但是,Java中提到的多态,在不特别说明的情况下都指动态多态)
c. 重写的条件:
- 参数列表必须完全与被重写方法的相同;
- 返回类型必须完全与被重写方法的返回类型相同;
- 访问级别的限制性一定不能比被重写方法的强;
- 访问级别的限制性可以比被重写方法的弱;
- 重写方法一定不能抛出新的检查异常或比被重写的方法声明的检查异常更广泛的检查异常
- 重写的方法能够抛出更少或更有限的异常(也就是说,被重写的方法声明了异常,但重写的方法可以什么也不声明)
- 不能重写被标示为final的方法;
- 如果不能继承一个方法,则不能重写这个方法。
d. 重载的条件:
- 被重载的方法必须改变参数列表;
- 被重载的方法可以改变返回类型;
- 被重载的方法可以改变访问修饰符;
- 被重载的方法可以声明新的或更广的检查异常;
- 方法能够在同一个类中或者在一个子类中被重载。
5. 继承(extends)与实现(implements)
继承(Inheritance):如果多个类的某个部分的功能相同,那么可以抽象出一个类出来,把他们的相同部分都放到父类里,让他们都继承这个类。
实现(Implement):如果多个类处理的目标是一样的(同样的目标),但是处理的方法方式不同(不同的处理方式),那么就定义一个接口,也就是一个标准,让他们都实现这个接口,各自实现自己具体的处理方法(自己去实现各自所需的方法内容),来处理那个目标。
继承指的是一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口)的功能,并可以增加它自己的新功能的能力。所以,继承的根本原因是因为要复用,而实现的根本原因是需要定义一个标准。
Java中支持一个类同时实现多个接口,但是不支持同时继承多个类。但是这个问题在Java 8之后也不绝对了。
class Car extends Benz implements GasolineCar, ElectroCar{
}
在接口中只能定义全局常量(static final)和无实现的方法(Java 8以后可以有defult方法);而在继承中可以定义属性方法,变量,常量等。
6. Java多继承的问题
在 Java 中,不允许“实现多继承”,即一个类不允许继承多个父类。但是 Java 允许“声明多继承”,即一个类可以实现多个接口,一个接口也可以继承多个父接口。由于接口只允许有方法声明而不允许有方法实现(Java 8以前),这就避免了 C++ 中多继承的歧义问题。
但是,Java不支持多继承,在Java 8中支持了默认函数(default method )之后就不那么绝对了。
虽然我们还是没办法使用extends同时继承多个类,但是因为有了默认函数,我们有可能通过implements从多个接口中继承到多个默认函数
7. Java的继承与组合
Java代码的复用技术有继承,组合以及代理三种具体的表现形式;
a. 定义:
- 继承是类与类或者接口与接口之间最常见的一种关系;继承是一种is-a关系。is-a表示"是一个"的关系;如:狗是一个动物
- 组合(Composition)体现的是整体与部分、拥有的关系,即has-a的关系。has-a表示"有一个"的关系,如狗有一个尾巴
b.区别和联系
- 在继承结构中,父类的内部细节对于子类是可见的。所以我们通常也可以说通过继承的代码复用是一种白盒式代码复用。(如果基类的实现发生改变,那么派生类的实现也将随之改变。这样就导致了子类行为的不可预知性;)
- 组合是通过对现有的对象进行拼装(组合)产生新的、更复杂的功能。因为在对象之间,各自的内部细节是不可见的,所以我们也说这种方式的代码复用是黑盒式代码复用。(因为组合中一般都定义一个类型,所以在编译期根本不知道具体会调用哪个实现类的方法)
- 继承,在写代码的时候就要指名具体继承哪个类,所以,在编译期就确定了关系。(从基类继承来的实现是无法在运行期动态改变的,因此降低了应用的灵活性。)
- 组合,在写代码的时候可以采用面向接口编程。所以,类的组合关系一般在运行期确定。
c. 优缺点对比
d. 如何选择
建议在同样可行的情况下,优先使用组合而不是继承。
因为组合更安全,更简单,更灵活,更高效。
继承要慎用,其使用场合仅限于你确信使用该技术有效的情况。一个判断方法是,问一问自己是否需要从新类向基类进行向上转型。如果是必须的,则继承是必要的。反之则应该好好考虑是否需要继承。《Java编程思想》
只有当子类真正是超类的子类型时,才适合用继承。换句话说,对于两个类A和B,只有当两者之间确实存在is-a关系的时候,类B才应该继承类A。《Effective Java》
8. 构造函数与默认构造函数
- 构造函数,主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。
- 一个类可以有多个构造函数,可根据其参数个数的不同或参数类型的不同来区分它们即构造函数的重载。
- 构造函数跟一般的实例方法十分相似;但是与其它方法不同,构造器没有返回类型,不会被继承,且可以有范围修饰符。
- 构造器的函数名称必须和它所属的类的名称相同。它承担着初始化对象数据成员的任务。
- 如果在编写一个可实例化的类时没有专门编写构造函数,默认情况下,一个Java类中会自动生成一个默认无参构造函数(默认构造函数)。默认构造函数一般会把成员变量的值初始化为默认值,如int -> 0,Integer -> null。
- 如果我们手动在某个类中定义了一个有参数的构造函数,那么这个默认的无参构造函数就不会自动添加了。需要手动创建!
9. 类变量、成员变量和局部变量
/**
* @author Hollis
*/
public class Variables {
/**
* 类变量
*/
private static int a;
/**
* 成员变量
*/
private int b;
/**
* 局部变量
* @param c
* c和d都是局部变量
*/
public void test(int c){
int d;
}
}
10. 成员变量和方法的作用域
区别:
- public : 表明该成员变量或者方法是对所有类或者对象都是可见的,所有类或者对象都可以直接访问
- private : 表明该成员变量或者方法是私有的,只有当前类对其具有访问权限,除此之外其他类或者对象都没有访问权限.子类也没有访问权限
- protected : 表明成员变量或者方法对类自身,与同在一个包中的其他类可见,其他包下的类不可访问,除非是他的子类。
- default(可以不写) : 表明该成员变量或者方法只有自己和其位于同一个包的内可见,其他包内的类不能访问,即便是它的子类;
11. Java如何实现平台无关性
a. 什么是平台无关性: 平台无关性就是一种语言在计算机上的运行不受平台的约束,一次编译,到处执行(Write Once ,Run Anywhere)
b. 好处:对于Java开发者来说,Java减少了开发和部署到多个平台的成本和时间。真正的做到一次编译,到处运行。
c. 编译原理基础:
d. 小结
对于Java的平台无关性的支持是分布在整个Java体系结构中的。其中扮演着重要角色的有Java语言规范、Class文件、Java虚拟机等。
- Java语言规范 通过规定Java语言中基本数据类型的取值范围和行为
- Class文件 所有Java文件要编译成统一的Class文件
- Java虚拟机 通过Java虚拟机将Class文件转成对应平台的二进制文件等
Java的平台无关性是建立在Java虚拟机的平台有关性基础之上的,是因为Java虚拟机屏蔽了底层操作系统和硬件的差异。
即:JVM只与字节码文件(.class文件)进行交互;虚拟机并不关心字节码是有哪种语言编译而来的
12. 实参与形参
-
形式参数:是在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传入的参数。
-
实际参数:在调用有参函数时,主调函数和被调函数之间有数据传递关系。在主调函数中调用一个函数时,函数名后面括号中的参数称为“实际参数”。
实际参数是调用有参方法的时候真正传递的内容,而形式参数是用于接收实参内容的参数。
13. 值传递与引用传递
-
值传递(pass by value)是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
-
引用传递(pass by
reference)是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
14. 8种基本数据类型
Java中有8种基本数据类型分为三大类。 -
字符型 char
-
布尔型 boolean
-
数值型
1.整型:byte、short、int、long2.浮点型:float、double
String不是基本数据类型,是引用类型。