本文主要是介绍Java基础(五)OOP面向对象之(三) 面向对象思想概述(续),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
13. 默认的构造方法
构造方法可分为两种:
隐含的默认构造方法(无参构造器);
程序显示定义的构造方法;
在Java语言中,每个类至少有一个构造方法。为了保证这一点,如果用户定义类中没有提供任何构造方法,那么在运行的时候JVM将自动提供一个隐含的默认构造方法。该构造方法没有参数,用public修饰,而且方法体为空,格式如下:
public ClassName(){} //隐含的默认构造方法
注意: 当程序显示的声明构造方法后,将不再自动生成隐式的构造方法。
在程序中也可以显示地定义默认构造方法。
如果类中显式定义了一个或多个构造方法,那么Java语言便不再分配隐含的默认构造方法。举例:
public class Sample{public Sample(int a) {System.out.println("My Constructor");}}创建Sample类对象的语句:Sample s1 = new Sample(); //编译出错Sample s2 = new Sample(1); //合法的
14. 子类
14.1. 通过生活中的例子推出Java中继承
什么是继承呢?生活中不乏这样的例子,张老头有个儿子张小头,张老头健在的时侯,张小头继承了张老头的坏脾气,国字脸,八字脚。张小头只有亲生爸爸张老头,张老头却有包括张小头在内的多个子女。
Java中类与类之间也有生活中类似的继承关系。在Java类继承关系中,对应于父亲的类叫父类,对应于儿子的类叫子类。父子类间的继承关系也叫“is a”关系。这种关系通过类声明上的extends关键字体现。
在Java内,一个类可以只能拥有一个继承和多个接口。一个子类只有一个父类,一个父类可有多个子类。
14.2. 为什么要继承?
- 站在巨人的肩膀上;通过继承,我们可以快速构建出一个带有丰富功能的新类;有了张老头,张小头年纪轻轻就可以买上上百万的新房;
- 不修改源代码,修改既有类的行为;通过继承,在子类中构建父类中一样的方法,可以改变父类方法的行为。张老头没有考上大学,通过张小头圆了其上大学的梦。
- 即能够快速的迭代开发/不更改过去的程序等兼容性
14.3. Object类简略介绍
所有的Java类都直接或间接地继承了java.lang.Object类。Object类是所有Java类的祖先,在这个类中定义了所有的Java对象都具有相同行为。
15. 继承
子类继承了父类的属性和方法:
1) 父子类同包,子类继承父类中public、protected和默认访问级别的成员变量和成员方法;
2) 父子类不同包,子类继承父类中public、protected的成员变量和成员方法;
注意:关于public/protected/private/默认访问关键字的具体用法,是封装性的核心要素,这在之后的文章内会提及。
那么继承有哪些细节呢?
- 构造器不能被继承!(因为构造函数属于父类独有,自然不能继承。)
- 方法和实例变量可以被继承
- 子类构造器隐式地调用父类的默认无参构造器;
- 如果父类中没有定义无参构造器,只定义了有参构造器,那么子类构造器则必须显式地调用父类的有参构造器(通过super(⋯)),且必须放置在第一条语句,否则会有语法错误。(这也是常会出现的问题,需要注意。)
- this()和super()在构造器中都必须为第一条语句,两者不能同时出现。
- 当一个子类继承了一个父类后,父类中所有的字段和方法都被子类继承拥有,子类可以任意的支配使用,每个子类对象中都拥有了父类中的所有字段。当构造一个子类的实例对象时,该对象的实例变量包括了子类本身以及父类中的所有实例变量,实例方法也包括了子类和父类中的所有实例方法。(详见子类类的构造流程)
- 子类构造器用来初始化子类中所有的实例变量,而父类构造器super(实参)用来初始化父类中所有的实例变量。所以在堆中为子类实例对象分配的内存区域中包括了子类和父类中所有初始化后的实例变。(详见子类类的构造流程)
16. 方法覆盖(重写 Override)
16.1 重写
方法覆盖只存在于子类和父类(包括直接父类和间接父类)之间。在同一个类中方法只能被重载,不能被覆盖;
16.2 静态方法(待测试)
- 父类静态方法不能被子类覆盖,但是可以被子类继承;
- 父类的静态方法不能被子类覆盖为非静态方法 //编译出错
- 子类可以定义与父类的静态方法同名的静态方法(但是这个不是覆盖 但是也不是重载?)
父类的非静态方法不能被子类覆盖为静态方法;//编译出错
即:静态只能被重写和继承。但是静态不能被覆盖为非静态,非静态也不能被覆盖为静态。
16.3 私有方法
- 私有方法,调用会采取就近原则。(不能被子类覆盖? 子类会继承父类的私有方法,但是根据private关键字原则,子类并不能使用父类的私有方法和私有对象,故也不存在覆盖的现象)
class Base {private String showMe() {return "Base";}public void print() {System.out.println(showMe());}
}public class Sub extends Base {private String showMe() {return "Sub";}public static void main(String args[]) {sub sub = new Sub();sub.print(); }}//打印出结果"Base", 因为print()方法在Base类中定义,因此调用在Base类中定义的,就近原则;//private类型的showMe(). 如将private换成public类型,其它代码不变,打印"Sub";
16.4 抽象方法:(之后会详细讨论抽象方法)
可以覆盖:
- 父类的抽象方法可以被子类覆盖为非抽象方法: 子类实现父类抽象方法;
- 父类的抽象方法可以被子类覆盖为抽象方法: 重新声明父类的抽象方法;
- 父类的非抽象方法可以被子类覆盖为抽象方法;( ???)
17. super关键字
17.1 为什么要使用super关键字?
- 子类中要访问父类方法或变量。
- 子类中调用父类的构造器
17.2 使用注意事项
- 只能在构造方法或实例方法内使用super关键字,在静态方法和静态代码块内不能使用super关键字。
- 在子类构造方法中如没有使用this关键字,会隐式调用父类的无参构造方法;
- 构造方法中this(…)和super(…)不能同时出现;
class Father() { public Father() {//这里第一行隐含一句代码: super();System.out.println("In Father()");}}class Son extends Father {}public class Test {public static void main(String[] args) {new Son(); //打印输出 In Father()}}-----------------------------------------------------------------------class Father() { public Father() {System.out.println("In Father()");}}class Son extends Father {public Son() {System.out.println("In Son()"); } }public class Test {public static void main(String[] args) {new Son(); //打印输出 In Father()// In Son()}}-----------------------------------------------------------------------class Father() { public Father(String name) {System.out.println("In Father() " + name);}}class Son extends Father {public Son() {System.out.println("In Son()"); } }public class Test {public static void main(String[] args) {new Son(); //编译出错, 子类会隐式调用父类中无参构造方法,而此时父类中不存在无参构造方法。}}-----------------------------------------------------------------------class Father() { public Father(String name) {System.out.println("In Father() " + name);}}class Son extends Father {public Son() {super("zs");System.out.println("In Son()"); } }public class Test {public static void main(String[] args) {new Son(); //打印输出://In Father() zs//In Son()}}-----------------------------------------------------------------------class Father() { public Father() {System.out.println("In Father()");}public Father(String name) {System.out.println("In Father(String name)");}}class Son extends Father {public Son() {this("zs");System.out.println("In Son()"); }public Son(String name) {System.out.println("In Son(String name)"); } }public class Test {public static void main(String[] args) {new Son(); //打印输出://In Father()//In Son(String name)//In Son()}}
18. 多态(也常称为 动态绑定 父类指针 父类空间/子类空间)
多态的俩中描述:
- 一个父类类型的引用可以指向他任何一个子类的对象;
[相同]类域的[不同]对象执行[同一]方法的时候会有[不同]的表现;(即父类对象 指向的是父类空间还是 子类空间 执行的调用的方法可能不同。)
多态是出现在具有继承关系的两个类的对象之间,所以它不像方法重载(发生在一个类中)在编译期间发生(也就是确定下来),而是在运行期间发生(确定下来)。
Java中的方法是在代码运行时动态绑定的。
多数情况下我们不能重新调用父类被覆盖掉方法的,但是万一需要调用可以采用如下实现方式:
- 第一种: 子类 重现的方法中 使用 super关键字 去调用父类中的方法或属性;
- 第二种:直接实例化 父类。
package com.us.demo.extend;class TransferBase{public void method(){System.out.println("Base");}
}
class TransExtend extends TransferBase{public void superMethod(){super.method();}public void method(){System.out.println("Trans");}
}
public class TransferExtendTest {public static void main(String []args){TransferBase trans = new TransExtend();trans.method();((TransferBase)trans).method();//没用 只有让指针重新指向父类的空间((TransExtend)trans).superMethod();// 可以 但是违背了多态的思想 有点鸡肋// 如果不是类内部,而是外部调用,比如你例子中的main方法,答案是
//
// 不能。你不能调用已经被覆盖掉的父类的方法。
//
// 这也是覆盖override的最初设计意图之一。
//
// 大多数时候,覆盖父类意味着子类想做些特殊的处理。如果能够跳过子类的特殊处理,就会打开一个无法控制的缺口,会导致很多很多问题。
//
// 唯一可以调用父类方法的地方,就只有类内部。子类自己控制,什么时候该调用父类,什么时候做自己的处理。}}
19. 类型转换
转换:
- 先使用instanceof 识别类型
- 子类型隐式地扩展到父类型(自动转换)
父类型必须显式地缩小到子类型
转换规则:被转换的实际对象类型一定是转换以后对象类型的自身或者子类。即大空间可以向小空间转换,小空间不能向大空间类型转换。
Person p = new Person(); Student s = (Student)p; //编译不会错,运行时错误Person p2 = new Student(); Student s = (Student)p2 或者 Person p = (Student)p2; 正确
在工作中,这些经常会使用到。
- 自动拆箱和自动装箱;
- 反射时候,因为基本数据类型都是由 Number类型 和 String类型组成的。
20. 继承总结
继承现象大总结:
- 子类重写父类方法,调用子类方法;
- 子类属性与父类同名(不管子类属性前修饰符如何均允许),如获取属性,看获取属性方法位置,如在父类中,获取的是父类属性,如在子类中,获取的是子类属性;(就近原则)
- 子类私有方法与父类私有方法同名,如调用该方法,看私有方法被调用的位置,如在父类中,调用的是父类方法,如在子类中,调用的是子类方法;(就近原则)
- 子类静态方法与父类静态方法同名,子类静态方法屏蔽父类静态方法。如调用该静态方法,看实例化对象时所声明的类型,如声明为父类,调用的是父类中静态方法,反之是子类中静态方法。
- 子类中的成员变量不会被覆盖,无多态特性,需要注意!
这篇关于Java基础(五)OOP面向对象之(三) 面向对象思想概述(续)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!