java面向对象里边包含了:继承 多态 重载 重写
下面是查询到的有用资料和自己的理解的结合
一、继承
1、继承:继承顾名思义,就是子类继承了父类的特征(java里边的特征是方法)。可以使用 extends 和 implements 这两个关键字来实现继承。
区别:extends是继承父类,只要那个类不是声明为final或者那个类定义为abstract的就能继承,JAVA中不支持多重继承,但是可以用接口来实现,extends只能继承一个类,implements可以实现多个接口.注:extend可以继承一个接口,但仍是一个接口,也需要implements之后才可用
e.g. class A extends B implements C,D,E
2、作用:先明确,大量重复的代码在编程中是十分不好的。如果我们想编写两个类,牛和马,那么他们共同的方法都有吃草
(1)extends 关键字例子
public class horse{
private String name;
public horse(String name){
this.name = name;
}
public void eatGrass(){}
public void sleep(){}
}
public class cow{
private String name;
public cow(String name){
this.name = name;
}
public void eatGrass(){}
public void sleep(){}
}
除了类型不一样,其他都一样,显得累赘。如果用了继承,让代码更简洁,变成总-分关系.两个方法直接继承了,修改以后:
public class grassAnimal{
private String name;
public grassAnimal(String name){
this.name = name;
}
public void eatGrass(){}
public void sleep(){}
}
public horse extends grassAnimal{
public horse(String name){
super(name);
}
}
public cow extends grassAnimal{
public horse(String name){
super(name);
}
}
注1:如何调用horse的sleep方法
grassAnimal a = new horse("horse");//向上转型
a.sleep();
但是如果horse有一个方法run,下面这样的写法是错的,因为编译的时候是使用grassAnimal的run方法来检查,如何能通过编译,运行的时候,才采用horse的run方法
grassAnimal a = new horse("horse");
a.run();
应该改成:
horse a = new horse("horse");
a.sleep();
下面这个例子更加清楚:
注2:一个例子
public class Wine {
public void fun1(){
System.out.println("Wine 的Fun.....");
fun2();
}
public void fun2(){
System.out.println("Wine 的Fun2...");
}
}
public class JNC extends Wine{
/**
* @desc 子类重载父类方法
* 父类中不存在该方法,向上转型后,父类是不能引用该方法的
* @param a
* @return void
*/
public void fun1(String a){
System.out.println("JNC 的 Fun1...");
fun2();
}
/**
* 子类重写父类方法
* 指向子类的父类引用调用fun2时,必定是调用该方法
*/
public void fun2(){
System.out.println("JNC 的Fun2...");
}
}
public class Test {
public static void main(String[] args) {
Wine a = new JNC();
a.fun1();
}
}
结果
Wine 的Fun.....
JNC 的Fun2...
只是因为实例化的JNC并没有fun1()无参数的方法,所以只能调用Wine的
(2)implement
如果使用interface来定义grassAnimal
public interface grassAnimal {
public void eatGrass();
public void sleep();
}
public class cow implements grassAnimal {
}
public class horse implements grassAnimal {
}
3、构造器
(1)解释:两种情况:父类的构造器没有参数,系统自动调用父类的无参构造器;父类的构造器有参数,需要通过super关键字才能调用父类的构造器(具体看例子分析)
(2)举例:
class SuperClass {
private int n;
SuperClass(){
System.out.println("SuperClass()");
}
SuperClass(int n) {
System.out.println("SuperClass(int n)");
this.n = n;
}
}
class SubClass extends SuperClass{
private int n;
SubClass(){
super(300);
System.out.println("SubClass");
}
public SubClass(int n){
System.out.println("SubClass(int n):"+n);
this.n = n;
}
}
public class TestSuperSub{
public static void main (String args[]){
SubClass sc = new SubClass();
SubClass sc2 = new SubClass(200);
}
}
输出结果
SuperClass(int n)
SubClass
SuperClass()
SubClass(int n):200
为什么会有第三句的出现呢?
解释:
1、子类不能继承父类的构造器。
2、继承父类的时候,构造器不写super,这个时候,编译器会自动地添加一个空参数的缺省super构造器(父类无参数的构造器),此时如果父类中没有空参数的缺省构造器,那就会导致一个编译错误。(意思是,子类的每一个方法都有super,如果有参数,那就用父类有参数的构造器,如果不写的话,编译器依旧会给你加上super,采用父类无参数的构造器,如果不存在这个无参数构造器,编译出错)
例如:subClass的第二个方法
public SubClass(int n){
System.out.println("SubClass(int n):"+n);
this.n = n;
}
补全后是,如果SuperClass没有空的构造器就编译出错了
public SubClass(int n){
super();
System.out.println("SubClass(int n):"+n);
this.n = n;
}
二、重载和重写
菜鸟教程
(图借鉴了菜鸟教程)
重载:Overloading (好多种,只是参数不同)
重写:Overriding(改变这个方法的实现方式)
三、多态
1、重写
2、接口
3、抽象方法
- 抽象类不能被实例化,只能被其他类继承
- 继承抽象类的子类必须把抽象类中的所有抽象成员都重写(实现)(除非子类也是抽象类)
- 抽象类就是为了重写→多态(代码重用)
引用看到的博客的一段话:“如何区分多态和继承”
继承:子类继承父类中所以的属性和方法,但是对于private的属相和方法,由于这个是父类的隐私,所以子类虽然是继承了,但是没有可以访问这些属性和方法的引用,所以相当于没有继承到。很多时候,可以理解为,没有继承。
多态:就是父类引用可以持有子类对象。这时候只能调用父类中的方法,而子类中特有方法是无法访问的,因为这个时候(编译时)你把他看作父类对象的原因,但是到了运行的时候,编译器就会发现这个父类引用中原来是一个子类的对像,所以如果父类和子类中有相同的方法时,调用的会是子类中的方法,而不是父类的。
可以这么说:编译时看父类,运行时看子类。