三、接口和继承
接口
接口是一组具有空主体的相关方法,所有方法默认都是抽象的
你可以使用关键字implements
在类声明中实现接口
如果类实现了一个接口,则该类必须实现接口的所有抽象方法
接口中声明的属性只能是public static final,即便没有显式的声明
继承
子类获取父类属性的方式
面向对象编程允许类从其他类继承常用的状态和行为
在 Java 编程语言中,每个类都可以有一个直接的父类,并且每个父类都可以有无限数量的子类
创建子类的语法很简单。在类声明的开头,使用extends
关键字,后跟要继承的类的名称:
class SubClass extends SuperClass {
// new fields and methods defining
}
对象转型
子类转父类(向上转型),可以直接自动转换
父类转子类(向下转型),需要强转,强转有风险,可能会丢失某些属性
到底能不能转换成功,要看引用类型到底指向的是哪种对象,instanceof是否为真
没有继承关系的两个类,互相转换,一定会失败,会出现编译错误
instanceof
instanceof 判断一个引用所指向的对象,是否是一个类的实例,或者该类父类的实例
在类型转换前需要判断instanceof,才可以转换
public class test {
public static void main(String[] args) {
//Object > String
//Object > Person > Men
//Object > Person > Women
/*
总结:
1、等号左边的引用类型,决定了是否编译错误。
左边的类型和右边的类有继承关系就可以编译通过
2、等号右边的对象类型,决定了结果的真假。
该类型是本类或子类对象都是真,
如果是父类对象或无继承关系则为假(父类对象不是子类的实例)
*/
Object obj = new Man();
System.out.println(obj instanceof Man);//true
System.out.println(obj instanceof Person);//true
System.out.println(obj instanceof Object);//true
System.out.println(obj instanceof Women);//false
System.out.println(obj instanceof String);//false
System.out.println("=========================");
Person p = new Man();
System.out.println(p instanceof Man);//true
System.out.println(p instanceof Person);//true
System.out.println(p instanceof Object);//true
System.out.println(p instanceof Women);//false
// System.out.println(p instanceof String);///编译错误,报错与否和p的类型有关,非继承关系报错
System.out.println("=========================");
Man m = new Man();
System.out.println(m instanceof Man);//true
System.out.println(m instanceof Person);//true
System.out.println(m instanceof Object);//true
// System.out.println(m instanceof Women);//编译错误,报错与否和m的类型有关,非继承关系报错
// System.out.println(m instanceof String);//编译错误,报错与否和m的类型有关,非继承关系报错
}
}
class Person {
}
class Man extends Person {
}
class Women extends Person {
}
重写
子类可以继承父类的对象方法,在继承后,重复提供该方法,就叫做方法的重写
如果没有重写机制,子类一旦继承了父类,所有方法都不能修改了。子类又想有所不同,实现起来就增加开发成本
B b = new A();,A和B 的方法都是静态的,要看B是什么类型的,决定调用谁的方法
如果A和B的重写方法不是静态的,要看等号右边的对象是new的谁,就调用谁
多态
多态,都是同一个类型,调用同一个方法,却能呈现不同的状态
要实现类的多态,需要如下条件:
1、父类(接口)引用指向子类对象
2、调用的方法有重写
作用:可以减少多种重复方法的创建
super
super调用父类的构造方法,必须在构造方法的第一位
super只能出现在子类的方法或构造方法中
super和this不能同时调用构造方法
抽象类
1、不嫩new这个抽象类,只能靠子类去实现
2、抽象类可以有非抽象方法,但包含抽象方法的类必须是抽象类
内部类
四种内部类:非静态内部类,静态内部类,匿名类,本地类
内部类必须声明在成员的位置,即与属性和方法平等的位置
本地类和匿名类一样,直接声明在代码块里面,可以是主方法,for循环里等等地方
非静态内部类:一个类里面定义一个非静态的类,语法: new 外部类().new 内部类()
非静态内部类,是可以直接访问外部类的private实例属性(因为先有外部类对象,后有非静态内部类)
//使用在内部类的存在前提有外部类对象的情况下
public class test {
public static void main(String[] args) {
//非静态内部类的使用
new test().new Person().print();
}
//非静态内部类定义
class Person{
public void print() {
System.out.println("我是非静态内部类的print方法");
}
}
}
静态内部类:在一个类里面声明一个静态内部类,语法:new 外部类.静态内部类()
在静态内部类里面不可以访问外部类的实例属性和方法(因为先有静态内部类,后有外部类对象)
除了可以访问外部类的私有静态成员外,静态内部类和普通类没什么大的区别
public class test {
public static void main(String[] args) {
//静态内部类的使用
new test.Person().print();
}
//静态内部类定义
static class Person{
public void print() {
System.out.println("我是静态内部类的print方法");
}
}
}
匿名类:在声明一个类的同时实例化它,使代码更加简洁精练
在匿名类中使用外部类的局部变量,外部类的局部变量必须修饰为final
避免操作内部类同名变量时,从而误操作了外部类的局部变量
在jdk8中,已经不需要强制修饰成final了,因为编译器偷偷的帮你加上了看不见的final
public class test {
public static void main(String[] args) {
//匿名类的定义
Person tem = new Person() {
@Override
public void meth() {
System.out.println("我是匿名类");
}
};
//匿名类的使用
tem.meth();
System.out.println(tem);//test$1@1b6d3586系统自动分配的类名
}
}
abstract class Person{
public Person() {
System.out.println("我是抽象类的构造方法");
}
public abstract void meth();
}
本地类
直接声明在代码块里面,可以是主方法,for循环里,是有名字的类。如果没名字叫匿名类
在本地类中使用外部类的局部变量,外部类的局部变量必须修饰为final
避免操作内部类同名变量时,从而误操作了外部类的局部变量
在jdk8中,已经不需要强制修饰成final了,因为编译器偷偷的帮你加上了看不见的final
public class test {
public static void main(String[] args) {
//声明一个本地类
class Person{
public Person() {
System.out.println("我是本地类的构造方法");
}
}
//使用本地类
Person p = new Person();
}
}
默认方法
默认方法是JDK8新特性,指的是接口也可以提供具体方法了,而不像以前,只能提供抽象方法
interface Person{
default public void meth() {
}
}
为什么会有默认方法
没有默认方法的时候,当接口中要增加一个方法,那么实现接口的所有类都得改动
有了默认方法后,实现接口的类可以不用改动就可以拥有接口增加的方法(默认方法不是抽象的,不需要被实现)
UML图
Unified Module Language,统一建模语言,可以很方便的用于描述类的属性,方法,以及类和类之间的关系
成员的作用域作为可选项,定义是在成员的开头,有以下四种:
+
Public-
Private#
Protected~
Package/Internal
除此之外,通过在 方法()
后面增加 「星号 *
」斜体表示抽象和「美元符号 $
」下划线表示静态属性
不同的逻辑关系定义如下:
Type | Description |
---|---|
`< | –` |
*-- | 组成关系 |
o-- | 集合关系 |
--> | 关联关系 |
-- | 实现连接 |
..> | 依赖关系 |
`… | >` |
.. | 虚线连接 |
练习题
1)多态练习
public class test {
public static void main(String[] args) {
Person p = new Person();
Man m = new Man("男人");
Women w = new Women("女人");
m.kill(w);
w.kill(m);
}
}
interface Mortal{
public void die();
}
class Person {
public String name;
public void kill(Mortal p){
System.out.println(this.name+"放大招");
p.die();
}
}
class Man extends Person implements Mortal{
public Man(String name) {
this.name = name;
}
@Override
public void die() {
System.out.println("击败了男人");
}
}
class Women extends Person implements Mortal{
public Women(String name) {
this.name = name;
}
@Override
public void die() {
System.out.println("击败了女人");
}
}
2)综合练习
public class test {
public static void main(String[] args) {
Spider s = new Spider(8);
Cat c = new Cat();
Fish f = new Fish();
// System.out.println(s.legs);
s.eat();
s.walk();
// System.out.println(c.legs);
c.setName("花猫");
System.out.println(c.getName());
c.eat();
c.play();
c.walk();
// System.out.println(f.legs);
f.setName("比目鱼");
System.out.println(f.getName());
f.eat();
f.play();
f.walk();
}
}
interface Pet{
String getName();
void setName(String name);
void play();
}
abstract class Animal{
protected int legs;
protected Animal(int legs) {
this.legs = legs;
}
public abstract void eat();
public void walk(){
System.out.println(this.legs+"条腿行走");
}
}
class Spider extends Animal{
protected Spider(int legs) {
super(legs);
}
@Override
public void eat() {
System.out.println("蜘蛛小口的吃");
}
}
class Cat extends Animal implements Pet{
String name;
public Cat() {
this("");
}
public Cat(String name) {
super(4);
this.name = name;
}
@Override
public void eat() {
System.out.println("猫在吃东西");
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public void play() {
System.out.println("猫在玩");
}
}
class Fish extends Animal implements Pet{
private String name;
protected Fish() {
super(0);
}
@Override
public void eat() {
System.out.println("鱼在吃小虾");
}
public void walk(){
System.out.println("鱼不能走且没有腿");
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public void play() {
System.out.println("小鱼在玩耍");
}
}