16. Java面向对象的三个特征与含义。
三大特征是:封装、继承和多态。
封装是指将某事物的属性和行为包装到对象中,这个对象只对外公布需要公开的属性和行为,而这个公布也是可以有选择性的公布给其它对象。在java中能使用private、protected、public三种修饰符或不用(即默认default)对外部对象访问该对象的属性和行为进行限制。简单的说,一个类就是一个封装了数据以及操作这些数据的代码的逻辑实体。在一个对象内部,某些代码或某些数据可以是私有的,不能被外界访问。通过这种方式,对象对内部数据提供了不同级别的保护,以防止程序中无关的部分意外的改变或错误的使用了对象的私有部分。
继承是指可以让某个类型的对象获得另一个类型的对象的属性的方法。它支持按级分类的概念。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。继承概念的实现方式有二类:实现继承与接口继承。实现继承是指直接使用基类的属性和方法而无需额外编码的能力;接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力。
多态:更倾向于使用java中的固定用法,即overriding(覆盖)和overload(过载)。多态则是体现在overriding(覆盖)上,而overload(过载)则不属于面向对象中多态的范畴,因为overload(过载)概念在非面向对象中也存在。overriding(覆盖)是面向对象中的多态,因为overriding(覆盖)是与继承紧密联系,是面向对象所特有的。多态是指父对象中的同一个行为能在其多个子对象中有不同的表现。也就是说子对象可以使用重写父对象中的行为,使其拥有不同于父对象和其它子对象的表现,这就是overriding(覆盖)。
多态是面向对象三大特征里相对难理解和表述的一个特征。
多态的定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)
多态存在的三个必要条件
一、要有继承;
二、要有重写;
三、父类引用指向子类对象。
/**
* @author:Mars
* @see:
* @创建日期:2018年1月18日
* @功能说明:
*/
public class Test {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println(a1.show(b));
System.out.println(a1.show(c));
System.out.println(a1.show(d));
System.out.println(a2.show(b));
System.out.println(a2.show(c));
System.out.println(a2.show(d));
System.out.println(b.show(b));
System.out.println(b.show(c));
System.out.println(b.show(d));
System.out.println(b.show(a1));
System.out.println(b.show(a2));
}
}
class A {
public String show(D obj) {
return ("A and D");
}
public String show(A obj) {
return ("A and A");
}
}
class B extends A {
public String show(B obj) {
return ("B and B");
}
public String show(A obj) {
return ("B and A");
}
}
class C extends B {}
class D extends B {}
17. Override和Overload的含义去区别。
方法的重写(Override)和重载(Overload)是Java多态性的不同表现。重写(Override)是父类与子类之间多态性的一种表现,而重载(Overload)是一个类中多态性的一种表现。
如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写(Overrid)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被屏蔽了。
如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型或有不同的参数次序,则称为方法的重载(Overloading)。不能通过访问权限、返回类型、抛出的异常进行重载。
1. Override 特点
1、覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果;
2、覆盖的方法的返回值必须和被覆盖的方法的返回一致;
3、覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类;
4、方法被定义为final不能被重写。
5、对于继承来说,如果某一方法在父类中是访问权限是private,那么就不能在子类对其进行重写覆盖,如果定义的话,也只是定义了一个新方法,而不会达到重写覆盖的效果。(通常存在于父类和子类之间。)
2.Overload 特点
1、在使用重载时只能通过不同的参数样式。例如,不同的参数类型,不同的参数个数,不同的参数顺序(当然,同一方法内的几个参数类型必须不一样,例如可以是fun(int, float), 但是不能为fun(int, int));
2、不能通过访问权限、返回类型、抛出的异常进行重载;
3、方法的异常类型和数目不会对重载造成影响;
4、重载事件通常发生在同一个类中,不同方法之间的现象。
5、存在于同一类中,但是只有虚方法和抽象方法才能被覆写。
其具体实现机制:
overload是重载,重载是一种参数多态机制,即代码通过参数的类型或个数不同而实现的多态机制。 是一种静态的绑定机制(在编译时已经知道具体执行的是哪个代码段)。
override是重写,重写是一种动态绑定的多态机制。即在父类和子类中同名元素(如成员函数)有不同 的实现代码。执行的是哪个代码是根据运行时实际情况而定的。
代码事例可参照16的例子,深入理解。
18. Interface与abstract类的区别。
1.abstarct类用关键字abstract修饰。
类中可以出现abstract方法,也可以就包含普通方法。(也就是说一旦出现了抽象方法,那这个类必定是抽象类)
不能创建实例对象,就是不能使用new运算符创建类的对象。
abstract类的对象可以成为子类对象的上转型对象,可以调用子类重写的方法。
abstract类是可以不用有abstract方法的。
若一个抽象类是另一个抽象类的子类,那么它可以重写父类的抽象类,也可以直接继承。
abstract方法:只允许声明;不能再添加final关键字修饰;也不允许使用static修饰该方法,即抽象方法必须是实例方法。
如下图,普通类中准备构建abstract方法,会报错
正确格式应为下图,抽象类中含有抽象方法。也就是一旦一个类中有抽象方法,那么该类一定是抽象类。
而且,抽象类不能被实例化,如果实例化,必须重写抽象方法,如下:
package com.ws.test;
/**
* @author WeiS
*/
public abstract class AbstractTest {
public abstract void method1();
public static void main(String[] args) {
AbstractTest test = new AbstractTest() {
@Override
public void method1() {
System.err.println("this is override");
}
};
}
}
2 interface
接口体中包含常量的声明(无变量)和抽象方法2部分。
只有抽象方法,没有普通方法。
常量的访问权限都是public的,而且都是static常量(允许省略public,final,static修饰符)
所有抽象方法的访问权限一定都是public的(允许省略public,static修饰符)。
当一个普通类实现了一个接口时,那么必须重写这个接口中的所有方法,而且访问权限只能是public.
接口也有实现权限之分。
若父类实现了某个接口,那么子类也就自然实现了该接口,子类也不必再显示地使用关键字implements声明实现这个接口。
接口可以被继承,可以通过关键字extends声明一个接口是另一个接口的子接口。由于接口的方法和常量都是public的,子接口讲继父接口的全部方法和常量。
19. Static class 与non static class的区别。
在java中我们可以有静态实例变量、静态方法、静态块。类也可以是静态的。
java允许我们在一个类里面定义静态类。比如内部类(nested class)。把nested class封闭起来的类叫外部类。在java中,我们不能用static修饰顶级类(top level class)。只有内部类可以为static。
静态内部类和非静态内部类之间到底有什么不同呢?下面是两者间主要的不同。
(1)内部静态类不需要有指向外部类的引用。但非静态内部类需要持有对外部类的引用。
(2)非静态内部类能够访问外部类的静态和非静态成员。静态类不能访问外部类的非静态成员。他只能访问外部类的静态成员。
(3)一个非静态内部类不能脱离外部类实体被创建,一个非静态内部类可以访问外部类的数据和方法,因为他就在外部类里面。
下面是网上找的一个图,很抽象,上下结合以及下面的代码实例看;package com.ws.test;
/**
*
* @author WeiS
*
*/
public class OuterClass {
private static String msg = "msg";
private String msg1 = "msg1";
// 静态内部类
public static class StaticInnerClass {
// 静态内部类只能访问外部类的静态成员
public void printMessage() {
// 试着将msg改成非静态的,这将导致编译错误
System.out.println("Message from nested static class: " + msg);
//Cannot make a static reference to the non-static field msg1
//System.out.println("Message from nested static class: " + msg1);
}
}
// 非静态内部类
public class NoStaticInnerClass {
// 不管是静态成员还是非静态成员都可以在非静态内部类中访问
public void display() {
System.out.println("Message from non-static nested class: " + msg);
System.out.println("Message from non-static nested class: " + msg1);
}
}
public static void main(String[] args) {
// 怎么创建静态内部类和非静态内部类的实例
// 创建静态内部类的实例
OuterClass.StaticInnerClass staticInnerClass = new OuterClass.StaticInnerClass();
// 创建静态内部类的非静态方法
staticInnerClass.printMessage();
// 为了创建非静态内部类,我们需要外部类的实例
OuterClass outer = new OuterClass();
OuterClass.NoStaticInnerClass inner = outer.new NoStaticInnerClass();
// 调用非静态内部类的非静态方法
inner.display();
// 我们也可以结合以上步骤,一步创建的内部类实例
OuterClass.NoStaticInnerClass innerObject = new OuterClass().new NoStaticInnerClass();
// 同样我们现在可以调用内部类方法
innerObject.display();
}
}