面向对象特征—继承
继承:
继承是面向对象程序设计不可缺少的设计思想,是实现代码可重用的根基,是提高代码可扩展性的主要途径。
继承是从已有的类中派生出新的类,新的类能吸收已有类的属性和行为,并能扩展新的能力。
- 在JAVA中使用extends关键字来表示继承关系。
- JAVA不支持多继承,单继承使JAVA的继承关系很简单,一个类只能有一个直接父类。
- 继承之后子类可以调用父类的所有非私有属性和非私有方法
何时使用继承?
- 符合is-a关系的设计,使用继承
- 将子类共有的属性和行为放到父类中
继承的形式:
[访问权限修饰符][修饰符] 子类名 extends 父类名{子类体}
public class Animal{
public void eat(){}
}
public class Dog extends Animal{
public void play(){}
}
//子类对象可以直接调用父类的方法,强调复用性
Dog dog = new Dog ();
dog.eat();
继承的传递性:
C类从B类继承,B类又从A类继承
那么C类就具有B类和A类的所有非私有属性和非私有方法
当一个没有继承任何一个类时,jvm会默认让类继承Object类
Object是 java为所有类提供的基类
继承中的构造方法:
- 子类构造方法总是先调用父类构造方法,默认情况下,调用父类无参构造方法
- 可以在子类构造方法的第一行,使用super关键字调用父类任意一个构造方法
- 如果用super,必须写在构造方法的第一句
- 如果子类的构造方法中没有显式地调用基类构造方法,则系统默认调用基类无参数的构造方法。
原因:子类创建后需要调用父类的方法,所以在创建子类对象是父类也需要同时被创建.
super关键字用途
super关键字代表父类的引用,在程序中主要的用途
在子类构造方法中要调用父类的构造方法,需要注意:super语句只能出现在子类构造方法体的第一行。
- 用“super.成员变量名”来引用父类成员变量
- 用“super.方法名(参数列表)”的方式访问父类的方法。
- 与this的区别,this通常指代当前对象,super通常指代父类。
方法的重写(OverRide) overload重载:
在子类中可以根据需要对从基类中继承来的方法进行重写。
方法重写规则
- 方法名相同、参数列表相同;
- 返回值类型相同;
- 访问权限相同
即与父类方法结构完全相同
注意:构造方法不能重写
应用场景:
当父类的方法实现不能满足子类需求时,可以对方法进行重写( override)
类之间关系—关联,依赖
关联关系:
对象和对象之间的连接。在Java中,关联关系的代码表现形式为一个类做为另一个类的属性类型存在。
即“有”的关系:”has-a”。
关联关系分为单向关联和双向关联:
单向关联: A类关联B类。
双向关联:A类关联B类,B类关联A类;
public class Phone {
private Person per;//关联Person类
}
public class Person {
private Phone phone;//关联Phone类
}
关联关系的多重性
-
一对一关联
-
一对多关联
解决一对多的关联的方案 -
集合
public class Classes{
}
public class Student{
private List Classess;
}
- 数组
public class Classes{
}
public class Student{
private Classes[] Classess;
}
依赖关系(use-a):
指一个类A使用到了另一个类B
依赖关系的特性:
这种关系是具有偶然性的、临时性的、非常弱的,但是类B的变化会影响到类A。
依赖具体表现:
在代码层面,依赖关系表现为类B作为参数被类A在某个method
方法中使用
例:
public class Person {
public void travel(Bus bus){
}
}
依赖与关联
关联是“HAS”关系,依赖是“USE”关系
A类关联B类,指的是B类对象作为A类的属性存在,称为“has”关系。
A类依赖B类,指的是B的对象作为A类的方法参数存在,称为“use”关系。
面向对象特征—多态
多态:
同一种事物,在不同时刻表现不同的状态
多态存在的三个必要条件:
- 要有继承(包括接口的实现)(前提条件)
- 要有重写(前提条件)
- 父类引用指向子类对象
当编译期类型是父类,运行期类型是子类时,被称为父类引用指向子类对象
class Animal{
……
}
class Cat extends Animal{
……
}
class Dog extends Animal {
……
}
Animal x = new Cat() //Animal 的引用指向Cat的对象
多态环境下对成员方法的调用
class Animal{
void show() {
System.out.println(“Anmial");
}
}
class Cat extends Animal{
void show() {
System.out.println(“cat");
}
}
…….
Animal x = new Cat()
x.show() //调用的方法和父类同名时,默认调用子类中的方法,子类中没有此方法时再调用父类的方法
简单的说:编译看左边,运行看右边。
多态环境下对静态成员方法的调用
class Animal{
static void show() {
System.out.println(“Animal");
}
}
class Cat extends Animal {
static void show() {
System.out.println(“Cat");
}
}
…….
Animal x = new Cat()
x.show() //调用的是动物类中的静态成员方法。
简单的说:编译和运行都看左边。
多态环境下对成员变量的调用
class Animal{
int num = 3;
}
class Cat extends Animal {
int num = 4;
}
Animal x = new Cat()
x.num; //调用的是动物类中的成员变量。
简单的说:编译和运行都看等号左边。
注意:变量不存在被子类覆写这一说法,只有方法存在覆写。
方法参数具有多态性
class Animal{
void eat() {}
}
class Cat extends Animal{
void eat() {}
}
class Dog extends Animal{
void eat(){}
}
//方法的形式参数类型是父类类型,而传递的实际参数可以是任意子类的对象
method(Animal animal){
animal .eat();
}
方法参数多态性的好处:提高代码的扩展性
向上转型
class Animal{
void eat(){ }
}
class Cat extends Animal{
void look() {
System.out.println("看家");
}
}
………
Animal x=new Cat() //向上造型,Cat对象提升到Animal对象
x.eat() //只能使用父类中的方法
x.look() //报错!不能使用子类中的方法
向上转型的作用是:提高程序的扩展性。
向下转型
class Animal{
void eat(){ }
}
class Cat extendsAnimal{
void look() {
System.out.println("看家");
}
}
………
Animal x=new Cat()
Cat m=(Cat)x; //向下转型
m.eat() ;
m.look();//子父类中的方法都可以使用
向下转型的作用是:为了使用子类中的特有方法。
final关键字
- final 用于声明属性,方法和类
- 属性:定义就必须直接赋值或者在构造方法中进行赋值,并且后期都不能修改。
- 方法:子类里不可被覆盖(重写)。
- 类:不能被定义为抽象类或是接口,不可被继承。
final属性赋值:
在声明时同时赋值,往往与static一起使用
声明时不赋值,必须在构造方法中逐一赋值
总的原则:保证创建每一个对象的时候,final属性的值是确定的
private int index;
private static final double pai=3.14;
private final int level;
public Test(){
level=0;
}
public Test(int index){
this.index=index;
level=1;
}
对参数做final修饰
在方法参数前面加final关键字,为了防止数据在方法体中被修改。
public class Demo12 {
private int a=1;
public void ww(final int a){
a=12;
}
}
抽象类
-
用abstract修饰的类就是抽象类。如果某个类中包含有抽象方法,那么该类就必须定义成抽象类。
-
抽象方法
- 抽象方法是一种特殊的方法:它只有声明,而没有具体的实现
- 抽象方法必须用abstract关键字进行修饰
-
抽象类可以有成员属性和非抽象的成员方法。
-
抽象类不能被实例化,但可以有构造函数,因为抽象类中含有无具体实现的方法,所以不能用抽象类创建对象。
-
抽象类只能用作基类,表示的是一种继承关系。继承抽象类的非抽象类必须实现其中的所有抽象方法,而已实现方法的参数、返回值要和抽象类中的方法一样。否则,该类也必须声明为抽象类。
-
构造方法和静态方法不可以修饰为abstract
抽象类,抽象方法,在软件开发过程中都是设计层面的概念。也就是说,设计人员会设计出抽象类,抽象方法,程序员都是来继承这些抽象类并覆盖抽象方法,实现具体功能。
接口
认识一下接口
public interface MyInterface {
int num = 10; //所有属性默认为: public static final
public void foo();//所有方法都是:public abstract
//其他方法
}
必须知道的接口特性
- 接口不可以被实例化
- 实现类必须重写接口的所有方法
- 实现类可以实现多个接口
- 接口中的变量都是静态常量
面向接口编程
接口存在的意义:java中一个类只能有一个父类,所以用接口可以实现多继承的逻辑 。
从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现。
接口的定义和使用
接口的定义:使用 interface 关键字用来声明一个接口。
public interface Animal {
String type="爬行";
int count=34;
void eat();
void sleep();
default void test1(){
System.out.println("测试一");
}
public static void test2(){//接口中的静态方法只能用类名调用
System.out.println("测试二");
}
}
public interface PersonFriend {
}
[访问修饰符] interface 接口名称 [extends 其他的接口名1,….其他的接口名n] {
// 声明常量
// 抽象方法
}
接口的使用:类使用implements关键字实现接口。在类声明中,Implements关键字放在class声明后面。
[访问修饰符] class 类名 implements 接口名1,接口名2……{ }
class Dog implements Animal ,PersonFriend{
@Override
public void eat() {
System.out.println("吃");
}
@Override
public void sleep() {
System.out.println("睡觉");
}
}
结合继承:
[访问修饰符] class 类名 extends 父类名 implements 接口名1,接口名2……{ }
接口的特性
- 接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字。
- 接口中每一个方法也是隐式抽象的,默认为public abstract 。
- 接口中声明的属性默认为 public static final 的;
- 接口不是被类继承了,而是要被类实现。
- 接口不能实例化对象(无构造方法),但可以声明对象的引用。(多态性)
- 多个类可以实现同一个接口。
- 一个类可以实现多个接口,但只能继承一个类。
- 与继承关系类似,接口与实现类之间存在多态性。
- 一个接口能继承其它多个接口。
- 当类实现接口的时候,类要实现接口中所有的方法。否则,类必须声明为抽象的类
接口和抽象类的区别
语法上的区别:
- 抽象类里可以有构造方法,而接口内不能有构造方法。
- 抽象类中可以有普通成员变量,而接口中不能有普通成员变量。
- 抽象类中可以包含非抽象的普通方法,而接口中所有的方法必须是抽象的。
- 抽象类中的抽象方法的访问类型可以是public
,protected和默认类型,但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型。 - 抽象类中可以包含静态方法,接口内不能包含静态方法。
- 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义 静态常量。
相同点:
抽象类和接口都不能用来创建对象