一,继承
1,概述
-多个类中存在相同的属性和行为时,把这些相同的内容提取到一个独立的类中
其他类就不用在重复定义这些内容,只需要通过extends关键字继承独立的类
class 子类 extends 父类{}
有了继承后,我们就可以在一个已经存在的类的基础上,继续扩展新的成员
class Student{
private String name;
private int age;
public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void eat(){}
}
class Teacher{
private String name;
private int age;
public Teacher() { } public Teacher(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void eat(){}
}
-我们发现上面2个代码成员变量 name,age一样
get和set方法也一样,吃睡方法也都一样
如果我继续定义工人类,医生类,。。。
他们也具备这些内容
每一次定义这样的类都要把这些重复内容定义一遍
非常麻烦,所以我们要想办法改进
-如何改进?
基本思路,把这些相同的内容提取出来单独存放到一个类中,只存一次
然后让其他类和这个单独的类产生一个关联,让这些类可以具备这些内容
而不用重复定义这些内容
-为了实现这样的效果,java就提供了一种技术: 继承
2,继承如何表示?
-我们把提取出来的类称为父类,基类,超类
-多个有重复内容的类称为,子类,派生类
-继承表示:使用关键字 extends
格式:
class Fu{}
class Zi extends Fu{}
package com.momo.demo;
public class Main {
public static void main(String[] args) {
Student s = new Student();
s.setAge(11);
s.setName("aaa");
System.out.println(s.getName()); System.out.println(s.getAge()); s.eat(); Teacher t = new Teacher("qwe",32); System.out.println(t.getName()); System.out.println(t.getAge()); t.eat(); }
}
//父类
class Person{
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void eat(){
System.out.println("吃饭。。");
}
}
//子类
class Student extends Person{
public Student() {
}
public Student(String name, int age) {
super(name,age);
}
}
//子类
class Teacher extends Person{
public Teacher() {
}
public Teacher(String name, int age) {
super(name,age);
}
}
3,好处
-提高了代码的复用性
-提高了代码的维护性
-类和类产生了关系,这个关系是多态的前提
其实这也是个弊端,耦合度增加了
-原则:低耦合,高内聚
4,继承特点
-java只能单继承,不能多继承
一个类只能有一个父类,不能有多个父类
-java可以多层继承(继承体系结构)
class A{}
class B{}
class C extends A{}
class D extends B{}
//class E extends A,B{}
//class E extends A extends B{}
class A{}
class B extends A{}
class C extends B{}
class D extends C{}
package com.momo.demo;
public class Demo2 {
public static void main(String[] args) {
Son s = new Son();
s.fun();
s.show();
}
}
class Ye{
public void show(){
System.out.println("爷爷");
}
}
class Ba extends Ye{
public void fun(){
System.out.println("爸爸");
}
}
class Son extends Ba{
}
5,继承注意事项
-子类只能继承父类所有非私有的成员
-子类不能继承父类构造方法,但是可以通过super访问父类构造方法
-不要为了部分功能而去继承
-什么时候可以使用继承?
继承体现的是is a 的关系
Person
Student
Teacher
动物
猫
狗
package com.momo.demo;
public class Demo3 {
public static void main(String[] args) {
}
}
class Aaa{
public void show1(){}
public void show2(){}
}
/class Bbb{public void show2(){}public void show3(){}}/
/*
- 发现bbb中出现了和aaa中一样的方法,所以就想用继承
- 这样不好,这样不仅有了show2,还多了show1,可以这个show1并不是我们想要的
- */
class Bbb extends Aaa{
public void show3(){}
}
package com.momo.demo;
public class Demo4 {
public static void main(String[] args) {
Sonn s = new Sonn();
s.fun();
s.show();
//s.method();找不到符号
}
}
class Fu{
private int a = 5;
public int b = 6;
private void method(){ System.out.println(a); System.out.println(b); } public void show(){ System.out.println(a); System.out.println(b); method(); }
}
class Sonn extends Fu{
public void fun(){
// System.out.println(a); a 在 com.momo.demo.Fu 中是 private 访问控制
System.out.println(b);
}
}
6,继承后成员变量的关系
-子类成员变量名和父类成员变量名不一样,这个简单
-子类成员变量名和父类成员变量名一样,在子类方法中访问的时候访问顺序是?
在子类方法中找,有就用
在子类成员位置找,有就用
在父类的成员位置找,有就用
如果还找不到,就报错(没有考虑父类的父类)
package com.momo.demo;
public class Demo5 {
public static void main(String[] args) {
Zi z = new Zi();
System.out.println(z.a);
System.out.println(z.b);
z.show();
}
}
class Father{
// public int a = 5;
public void fun(){
int a = 456;
}
}
class Zi extends Father{
// public int a = 555;
public int b = 6;
public void show(){ // int a = 55555; System.out.println(a); }
}
7,super关键字
-super的用法和this很像
this表示本类对象的引用
super表示父类对象的引用
-他们都有如下用法
访问成员变量
this.成员变量
super.成员变量
访问构造方法
this(...)
super(...)
访问成员方法
this.成员方法(...)
super.成员方法(...)
package com.momo.demo;
/*
- 要访问子类成员a?
- 要访问父类成员a?
- */
public class Demo6 {
public static void main(String[] args) {
S s = new S();
s.show();
}
}
class F{
public int a = 5;
}
class S extends F{
public int a = 6;
public void show(){
int a = 7;
System.out.println(a);
System.out.println(this.a);
System.out.println(super.a);
}
}
8,继承后构造方法的关系
-子类中的所有构造方法默认都会访问父类的无参构造。为什么?
因为子类会继承父类中的数据,可能还要使用父类中的数据
所以子类初始化完成之前,一定要先完成父类数据的初始化
子类继承父类之后,子类中的所有构造方法第一句都是
super()
package com.momo.demo;
/*
- 要访问子类成员a?
- 要访问父类成员a?
- */
public class Demo6 {
public static void main(String[] args) {
S s = new S();
//s.show();
S s2 = new S(123);
}
}
class F{
public F(){
System.out.println("父无参");
}
public F(int i){
System.out.println("父带参");
}
public int a = 5;
}
class S extends F{
public S(){
// super();
System.out.println("ZI无参");
}
public S(int i){
super();
System.out.println("ZI带参");
}
public int a = 6;
public void show(){
int a = 7;
System.out.println(a);
System.out.println(this.a);
System.out.println(super.a);
}
}
-如果父类中没有无参构造怎么办?
子类为什么要访问父类的构造方法?是为了完成父类数据初始化来供子类使用
既然没有无参构造,肯定有带参构造,那么就可以使用带参构造来显示完成
父类数据初始化操作。super(...)
通过super显示调用父类的带参构造
package com.momo.demo;
/*
- 注意:super或this必须是第一条语句
- */
public class Demo6 {
public static void main(String[] args) {
S s = new S();
//s.show();
S s2 = new S(123);
}
}
class F{
/* public F(){
System.out.println("父无参");
}*/
public F(int i){
System.out.println("父带参");
}
public int a = 5;
}
class S extends F{
public S(){
// super();
//super(123);
this(123);
System.out.println("ZI无参");
}
public S(int i){
super(123);
// super();
System.out.println("ZI带参");
}
public int a = 6;
public void show(){
int a = 7;
System.out.println(a);
System.out.println(this.a);
System.out.println(super.a);
}
}
package com.momo.demo;
/*
- 子父类的初始化顺序
- 代码块的执行顺序和次数
- */
public class Demo7 {
public static void main(String[] args) {
Y y = new Y();
// y.show();
}
}
class X{
static{
System.out.println("帅哥");
}
{
System.out.println("美女");
}
public int a = 5;
public X(){
System.out.println("我");
}
}
class Y extends X{
static{
System.out.println("大长腿");
}
{
System.out.println("萝莉");//帅哥,大长腿,美女,我,萝莉,是,
}
public int a = 6;
public Y(){
System.out.println("是");
}
public void show(){
int a = 7;
System.out.println(a);
System.out.println(this.a);
System.out.println(super.a);
System.out.println("屌丝");
}
}
package com.momo.demo;
/*
- 子父类的初始化顺序
- 一个类的初始化过程
- */
public class Demo8 {
public static void main(String[] args) {
c c = new c();
}
}
class a{
b b = new b();
a(){
System.out.println("a");
}
}
class b{
b(){
System.out.println("b");
}
}
class c extends a{
b b = new b();
c(){
System.out.println("c");
}
}
9,继承后成员方法的关系
-子类中的方法和父类中的方法不一样这个简单
-子类中的方法和父类中的方法一样,通过子类对象调用的时候
先在子类中找,有就用
在父类中找,有就用
还没有,就报错(没有考虑父类的父类)
package com.momo.demo;
public class Demo9 {
public static void main(String[] args) {
Zii z = new Zii();
z.fun();
z.show();
// z.aaa();
}
}
class Fa{
public void show(){
System.out.println("fushow");
}
}
class Zii extends Fa{
public void fun(){
System.out.println("zifun");
}
/* public void show(){
System.out.println("zishow");
}*/
}
10,方法重写
-上面案例中子类中出现了和父类中一摸一样的方法声明
的这种现象我们称为方法的重写(复写,覆盖)
-使用特点:
方法名不同,调用对应的
方法名相同,重写之后用的是子类自己的
-方法重写的应用
子类需要父类的功能,但是功能的主题子类有自己特有的内容的时候
我们就可以重写父类方法
这样既可以延续父类的功能,又可以定义自己特有的内容。
package com.momo.demo;
/*
- 最早的手机只能打电话
- 随着科技不断进步,现在已经研究除了很多新手机
- 不仅仅可以打电话,还有很多其他功能
- 在打电话的同时还可以干什么事情(显示通话时长,显示来电归属地信息...)
- 我们按照分析定义了新手机类,重新编写了打电话方法,添加了功能
- 但是不好,因为新手机是不是手机? 是手机,新手机应该继承手机类
- 而且打电话的功能是手机本身就具备的基本功能
- 这个功能在新手机中不用在重复编写,但是不编写这个代码,又大不了电话了。
- 最终还是要加上这个功能,由于它继承了手机类,所以我们可以直接使用父类的功能即可
- 通过super关键字调用父类已经实现过的功能,再去添加自己特有内容即可
- / public class Demo10 { public static void main(String[] args) { NewPhone np = new NewPhone(); np.call("默默"); } } /
- 定义一个手机类
- */
class Phone{
public void call(String name){
//可能真正完成这个功能需要500行代码
System.out.println("给"+name+"打电话");
}
}
//新手机
class NewPhone extends Phone{
public void call(String name){
//System.out.println("给"+name+"打电话");
super.call(name);
System.out.println("通话时长");
System.out.println("归属地信息");
}
//很多其他功能
}
11,方法重写的注意事项
-父类中私有的方法不能被重写
私有的无法继承,谈不上重写
-子类重写父类方法时,访问权限不能更低,最好一致
-父类中的静态方法,子类也必须使用静态方法来重写
注意:这个本质上不是重写,只是现象上如此
package com.momo.demo2;
public class Demo1 {
public static void main(String[] args) {
Son s = new Son();
s.show();
s.fun();
}
}
class Father{
/* private void show(){
System.out.println("privatefushow");
}*/
/* public void show(){
System.out.println("fushow");
}*/
void show(){
System.out.println("fushow");
}
public static void fun(){
System.out.println("fustatic");
}
}
class Son extends Father{
/* private void show(){
System.out.println("privatezishow");
}//
public static void main(String[] args) {
Son s = new Son();
s.show();
}*/
//正在尝试分配更低的访问权限; 以前为public
/void show(){System.out.println("zishow");}/
public void show(){ System.out.println("zishow"); } // 被覆盖的方法为static /*public void fun(){ System.out.println("zistatic"); }*/ public static void fun(){ System.out.println("zistatic"); }
}
12,相关问题
-方法重写和重载的区别
-方法重载可以改变返回值类型码?重载跟返回值类型无关(两同一不同,同一类同一方法名,不同参数)
-this和super的区别以及用法
13,继承练习(标准代码)
-先分析在实现
分析:从具体到抽象的过程
实现:从抽象到具体的过程
-老师和学生案例
-猫和狗案例
分析:从具体到抽象的过程
猫:
成员变量:name,age,color
构造方法:无参,带参
成员方法:get和set,eat,sleep,抓老鼠
狗:
成员变量:name,age,color
构造方法:无参,带参
成员方法:get和set,eat,sleep,看门
共性内容:
成员变量:name,age,color
构造方法:无参,带参
成员方法:get和set,eat,sleep
提取一个父类---动物类
实现:从抽象到具体的过程
动物类:
成员变量:name,age,color
构造方法:无参,带参
成员方法:get和set,eat,sleep
猫继承动物:
构造方法:无参,带参
成员方法:抓老鼠
狗继承动物:
构造方法:无参,带参
成员方法:看门
测试:
无参+set方法
带参
//父类
class Person{
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void eat(){
System.out.println("吃饭。。");
}
}
//子类
class Student extends Person{
public Student() {
}
public Student(String name, int age) {
super(name,age);
}
public void study(){}
}
//子类
class Teacher extends Person{
public Teacher() {
}
public Teacher(String name, int age) {
super(name,age);
}
public void teach(){}
}
day7,
7,final关键字
-继承中有个现象叫重写, 父类的功能就会被子类的覆盖掉。
有些时候不想让子类重写,为了实现这样的效果,java就带着final关键字来了。
-final最终的意思
可以修饰类,方法,变量
package com.momo.demo;
public class Demo8 {
public static void main(String[] args) {
Bb b = new Bb();
b.show();
}
}
class Aa{
public final void show(){
System.out.println("aaa");
}
}
class Bb extends Aa{
// 被覆盖的方法为final
/public void show(){System.out.println("bbb");}/
}
-修饰类:不能被继承
-修饰方法:方法不能被重写
-修饰变量:变成常量(自定义常量)
package com.momo.demo;
public class Demo8 {
public static void main(String[] args) {
/* Bb b = new Bb();
b.show();*/
int a = 5; a = 55; System.out.println(a); // final int b = 6; // b = 66;法为最终变量b分配值 final int b; b = 6; System.out.println(b); }
}
final class Aa{
public final void show(){
System.out.println("aaa");
}
}
//无法从最终com.momo.demo.Aa进行继承
/class Bb extends Aa{// 被覆盖的方法为final//public void show(){System.out.println("bbb");}//}/
8,相关问题
-final修饰变量的问题
基本类型:值不能变
引用类型:地址值不能变
package com.momo.demo;
public class Demo9 {
public static void main(String[] args) {
final int a = 5;
System.out.println(a);
final Cat c = new Cat(); System.out.println(c); // c = new Cat();无法为最终变量c分配值 // System.out.println(c); c.age = 22; System.out.println(c.age); }
}
class Cat{
int age = 11;
}
-final修饰成员变量的初始化时机(非静态的)
在对象构造完成之前即可
package com.momo.demo;
public class Demo9 {
public static void main(String[] args) {
final int a = 5;
System.out.println(a);
final Cat c = new Cat(); System.out.println(c); // c = new Cat();无法为最终变量c分配值 // System.out.println(c); //c.age = 22; System.out.println(c.age); // c.age = 33; 无法为最终变量age分配值 System.out.println(c.age); }
}
class Cat{ final int age; Cat(){ age = 22; // age = 22; } }
一,多态
1,概述
-同一事物在不同时刻表现出来的不同状态
-父类引用指向子类对象
人类
老师类
学生类
老师类 老师 = new 老师类(); 学生类 学生 = new 学生类(); //多态 人类 人 = new 老师类(); 人类 人 = new 学生类();
2,前提和体现
-前提:有继承关系
有方法重写(不重写没有意义了)
-体现:父类引用指向子类对象
package com.momo.demo;
public class Demo9 {
public static void main(String[] args) {
/* Cat c = new Cat();
c.eat();
Dog d = new Dog(); d.eat();*/ //多态 Animal a = new Cat(); a.eat(); a = new Dog(); a.eat(); }
}
class Animal{
public void eat(){
System.out.println("吃草");
}
}
class Cat extends Animal{
}
class Dog extends Animal{
}
3,多态下成员的访问特点
-成员变量
编译看父类,运行看父类
-构造方法
创建子类对象,访问父类构造。
-成员方法
编译看父类,运行看子类
-静态方法
编译看父类,运行也看父类
(静态和类相关)
package com.momo.test;
public class Demo1 {
public static void main(String[] args) {
/* Zi z = new Zi();
System.out.println(z.a);
System.out.println(z.b);
z.show();
z.method();
z.fun();*/
//多态 Fu f = new Zi(); System.out.println(f.a); // System.out.println(f.b);//找不到符号 f.show(); // f.method();找不到符号 f.fun(); }
}
class Fu{
Fu(){
System.out.println("aa");
}
public int a = 5;
public void show(){ System.out.println("fushwo"); } public static void fun(){ System.out.println("fustaticfun"); }
}
class Zi extends Fu{
Zi(){
System.out.println("bbb");
}
public int a = 55;
public int b = 66;
@Override public void show() { System.out.println("zishow"); } public void method(){ System.out.println("zimethod"); } public static void fun(){ System.out.println("zistaticfun"); }
}
4,多态的好处和弊端
-好处:
提高了复用性(继承)
提高了维护性(继承)
提高了扩展性(多态)
package com.momo.test;
public class Demo2 {
public static void main(String[] args) {
//我喜欢猫
Cat c1 = new Cat();
/* c1.eat();
c1.sleep();/// useCat(c1);// AnimalTools.useCat(c1);AnimalTools.useAnimal(c1);//我很喜欢猫,又养一只Cat c2 = new Cat();// AnimalTools.useCat(c2);// useCat(c2);/
c2.sleep();/AnimalTools.useAnimal(c2);//我非常喜欢猫,再养一只Cat c3 = new Cat();// AnimalTools.useCat(c3);/
c3.sleep();/// useCat(c3);AnimalTools.useAnimal(c3);//..../
* 问题:我养了很多猫,每次都创建对象 这个没有问题
* 问题在于调用方法,每次调用的都是一样的方法,只是对象名不一样。
* 所以需要改进。如何改进?
* 可以编写一个方法,通过这个方法去调用其他所有方法,参数就不不同的对象
*
* 有了方法后,就可以改进调用方法,调用简单了。
* */
System.out.println("--------------");
//我喜欢狗
Dog d1 = new Dog();
// AnimalTools.useDog(d1);
/*d1.eat();
d1.sleep();
/AnimalTools.useAnimal(d1);// useDog(d1);//我很喜欢狗Dog d2 = new Dog();//AnimalTools.useDog(d2);/
d2.sleep();*/
// useDog(d2);
AnimalTools.useAnimal(d2);
//出现和上面一样的问题,应该继续编写方法来改进调用方式
/* //使用狗对象所有方法的方法
public static void useDog(Dog d){
d.eat();
d.sleep();
}
//使用猫对象所有方法的方法
public static void useCat(Cat c){
c.eat();
c.sleep();
}//
* 根据分析,我们写了这2个方法,目前时再测试类中写的,合适码?
* 不合适。 应该写在哪里?
* 目前来说不管写在测试类,动物类,猫类,狗类 都不合适
* 因为这两个方法不是动物本身就具备的功能。
* 而是我们为了方便使用创建的快捷方法,是一种方便使用的工具。
*
* 所以我们应该额外定义一个工具类,来存储这些方法。
* 根据分析进行改进,改进后的调用方式就变了。
* /// AnimalTools.useDog(d1);// AnimalTools.useDog(d2);/
* 如果我后面又喜欢 ?? ,??,??,??,.... 这些动物
* 定义对应的类,继承动物类,重写对应的方法 这些都没有问题
* 每次为了方便使用还要再工具类中添加对应的use方法, 这个有问题
* 因为一旦出错,就会导致整个工具类无法使用。
* */
System.out.println("--------------");
Pig p = new Pig();
// AnimalTools.usePig(p);
AnimalTools.useAnimal(p);
}
}
class Animal{
String name;
String color;
String gender;
int age;
public void eat(){ System.out.println("吃"); } public void sleep(){ System.out.println("睡"); } public void show(){ System.out.println(name+"---"+age+"---"+color+"---"+gender); }
}
class Cat extends Animal{
public void eat(){
System.out.println("猫吃鱼");
}
public void sleep(){
System.out.println("猫蜷着睡");
}
}
class Dog extends Animal{
public void eat(){
System.out.println("狗吃骨头");
}
public void sleep(){
System.out.println("狗趴着睡");
}
}
class Pig extends Animal{
public void eat(){
System.out.println("??吃饲料");
}
public void sleep(){
System.out.println("??躺着睡");
}
}
//动物工具类
/*
- 工具就是为了方便使用,方法就写成静态的
- /
class AnimalTools{private AnimalTools(){}//使用狗对象所有方法的方法/
d.eat();
d.sleep();
}
//使用猫对象所有方法的方法
public static void useCat(Cat c){
c.eat();
c.sleep();
}
public static void usePig(Pig p){
//int a = "a";
p.eat();
p.sleep();
}*/
public static void useAnimal(Animal a){
//父类引用指向子类对象,,多态。。。
//Animal a = new Dog()
//Animal a = new Cat()
//Animal a = new Pig()
//Animal a = new She()
a.eat();
a.sleep();
}
}
-弊端:
多态情况下无法访问子类特有内容(弊端)
我就要访问怎么办?
创建子类对象
把父类的引用强转成子类的引用(向下转型)
向上转型
Fu f = new Zi();
向下转型
Zi z = (Zi)f;
注意:f必须是能够转换成Zi的
ClassCastException 类型转换异常
Animal a = new Cat(); Cat c = (Cat)a; c.eat(); a = new Dog(); //Dog d = (Dog)a; //ClassCastException 类型转换异常 // Cat cc = (Cat)a; // cc.eat(); // d.eat();
package com.momo.test;
public class Demo3 {
public static void main(String[] args) {
Father f = new Son();
f.show();
// f.fun();找不到符号
//向下转型 Son s = (Son)f; s.fun(); s.show(); }
}
class Father{
public void show(){
System.out.println("fushow");
}
}
class Son extends Father{
public void show(){
System.out.println("zishow");
}
public void fun(){ System.out.println("zifun"); }
}
5,多态练习(多态标准写法)
-老师和学生
-猫狗案例
package com.momo.test;
public class Demo4 {
public static void main(String[] args) {
/* A a = new B();
a.show();*/
B b = new C(); b.show(); }
}
class A{
public void show(){
show2();
}
public void show2(){
System.out.println("高");
}
}
class B extends A{
public void show() {
super.show();
}
@Override
public void show2() {
System.out.println("富");
}
}
class C extends B{
@Override
public void show() {
super.show();
}
@Override public void show2() { System.out.println("帅"); }
}
二,抽象类
1,概述
-前面案例提取出来的父类,不是一个具体的事物,不应该new
所以我们应该声明成抽象类。
-父类中的方法不应该给出具体的实现,也应该声明为抽象方法
2,特点
-抽象类,抽象方法都要用 abstract来修饰。
-抽象类中不一定有抽象方法,但是有抽象方法的类必须是抽象类
-抽象类本身不能实例化,但是可以依赖多态实现实例化---抽象类多态
通过具体的子类实现实例化
-抽象类的子类:
可以是抽象类,可以不重写抽象方法
也可以是具体类,必须重写父类中的所有抽象方法
package com.momo.test;
public class Demo5 {
public static void main(String[] args) {
//Catt s = new Catt();
// s.eat();
//抽象类多态 Anima p = new Dogg(); p.eat(); /* * 这个有问题, 我创建了一个动物对象 ,动物?到底是什么动物? * Animal a = new Animal(); * 动物?到底是什么动物? 不应该new 它不是一个具体的事物 * 它是一个抽象的事物,这个类应该是一个抽象类,抽象类也要用 abstract来修饰 * 只有具体的猫或这狗才是具体的事物。 * 不同的动物吃的不一样, 所以动物类中的eat方法不应该给出具体的实现 * 应该强制要求子类必须重写 ,如何实现? * java带着关键字 abstract 来了。 * 一个没有具体实现的方法(没有{方法体}方法)我们应该定义为抽象方法, 抽象方法要用abstract 修饰 * 一个类中如果有了抽象方法,这个类也应该定义为抽象类。 * */ // Anima pp = new Anima(); com.momo.test.Anima是抽象的; 无法实例化 //pp.eat(); }
}
abstract class Anima{
/* public void eat(){
System.out.println("吃");
}*/
//没有方法体的方法要定义为抽象方法
public abstract void eat();
}
abstract class Catt extends Anima{
/* public void eat(){
System.out.println("猫吃鱼");
}*/
}
class Dogg extends Anima{
public void eat(){
System.out.println("狗吃骨头");
}
}
3,抽象类的成员特点
-成员变量
可以是变量,也可以是常量
-构造方法
有,但是不能造对象
用于子类访问父类数据初始化的。
-成员方法
抽象的,要求子类必须做的
非抽象的,给子类继承的,提高复用性
package com.momo.test;
public class Demo6 {
public static void main(String[] args) {
Animall aa = new Tiger();
System.out.println(aa.a);
aa.a = 55;
System.out.println(aa.a);
System.out.println(aa.b);
aa.fun();
aa.show();
// Animall a = new Animall();com.momo.test.Animall是抽象的; 无法实例化 }
}
abstract class Animall{
int a = 5;
final int b = 6;
Animall(){ System.out.println("wucan"); } Animall(int a){ System.out.println("daican"); } abstract void show(); public void fun(){ System.out.println("aaa"); }
}
class Tiger extends Animall{
@Override void show() { System.out.println("dfdfd"); }
}
4,抽象类练习
-猫狗案例
分析:从具体到抽象
具体事物:猫和狗
猫:
成员变量:姓名,年龄,颜色。。。
构造方法:无参,带参
成员方法:get,set,eat,sleep, catchMouse。show。。。
狗:
成员变量:姓名,年龄,颜色。。。
构造方法:无参,带参
成员方法:get,set,eat,sleep, lookDoor。show。。。
有共性内容,提取父类动物类,不同的动物吃的不一样,吃应该是抽象的, 那么这个类也应该是抽象类。 抽象动物类: 成员变量:姓名,年龄,颜色。。。 构造方法:无参,带参 成员方法:get,set,abstract eat(),sleep, show。。。 实现:从抽象到具体 定义抽象动物类 成员变量:姓名,年龄,颜色。。。 构造方法:无参,带参 成员方法:get,set,abstract eat(),sleep, show。。。 狗类继承动物类 成员变量: 构造方法:无参,带参 成员方法:重写eat ,添加 lookDoor。 猫类继承动物类 成员变量: 构造方法:无参,带参 成员方法:重写eat ,添加 catchMouse 测试类测试: 具体类测试: 无参+set 带参 多态测试:向下转型 无参+set 带参
-老师和学生案例
-我们要设计一个员工系统,需要对员工类进行设计,
员工包含3个属性:工号,姓名,工资
经理也是员工,除了上面3个属性之外,还多了一个奖金属性
请使用继承思想设计员工类和经理类,提供必要的方法可以进行属性访问
并测试。。。
5,抽象类的相关问题
-一个类如果没有抽象方法,可以定义为抽象类码?有什么意义?
-抽象关键字不能和哪些关键字共存?
private 冲突 非法的修饰符组合: abstract和private
final 冲突 非法的修饰符组合: abstract和final
static 冲突 非法的修饰符组合: abstract和static
三,接口
1,概述
-前面的猫狗案例,猫狗除了吃睡玩,然后就是看门,抓老鼠。
现在社会中有中职业驯兽师,可以训练出会钻火圈的猫,会计算的狗,....
这些额外的功能不是动物本身就具备的,是训练出来的,所以这些功能
不能定义到动物类中,所以为了体现事物的扩展性,java就提供了接口
来定义这些扩展功能,再接口中这些功能不能给出具体的实现(不同动物训练方式不一样)
将来哪些具体的动物被训练了,这部分动物去实现接口中的这些功能即可
2,特点
-定义接口使用关键字 interface
格式: interface 接口名{}
-实现接口用 implements 关键字
格式:class 类名 implements 接口名{}
-接口本身不能实例化
但是可以依赖具体的实现类实现实例化---接口多态
具体类多态:几乎不用
抽象类多态:常用
接口多态:常用
-接口的实现类
可以是抽象类,可以不重写, 意义不大
可以是具体类,必须重写所有抽象方法
package com.momo.test;
public class Demo7 {
public static void main(String[] args) {
//com.momo.test.AniamlInterface是抽象的; 无法实例化
//AniamlInterface ai = new AniamlInterface();
//接口多态
AniamlInterface ai = new Snake();
ai.fireCircle();
ai.fun();
//ai.show();找不到符号
Snake ss = (Snake) ai; ss.show(); }
}
interface AniamlInterface{
//接口抽象方法不能带有主体
/* public void fireCircle(){
System.out.println("钻火圈");
}*/
//接口中的方法有默认修饰符 public abstract 但是建议自己写上 void fireCircle(); public abstract void fun();
}
abstract class Lion implements AniamlInterface{
}
class Snake implements AniamlInterface{
@Override public void fireCircle() { System.out.println("bbb"); } @Override public void fun() { System.out.println("aaa"); } public void show(){ System.out.println("adf"); }
}
3,接口的成员
-成员变量:
只能是静态常量,有默认修饰符 public static final
-构造方法:
没有构造方法,接口用来定义扩展功能的
-成员方法:
有默认修饰符 public abstract
只能是抽象方法(针对我们自己定义的普通方法)
可以有默认的非抽象方法
可以有静态的非抽象方法
package com.momo.test;
public class Demo8 {
public static void main(String[] args) {
/* Inter i = new InterImp();
System.out.println(i.a);
// i.a = 55;无法为最终变量a分配值
System.out.println(i.a);
System.out.println(i.b);*/
//说明了 其实还有一个默认修饰符 static System.out.println(Inter.a); System.out.println(Inter.b); }
}
interface Inter{
int a = 5;//实际上不是一个变量,默认修饰符 final
final int b = 6;
public static final int c = 7;
//接口中的成员变量有默认修饰符 public static final ,接口中的成员变量只能是静态的常量
}
class InterImp implements Inter{
}
public class Demo7 {
public static void main(String[] args) {
AniamlInterface ai = new Snake();
ai.aaa();
// ai.bbb();
AniamlInterface.bbb(); }
}
interface AniamlInterface{
//接口抽象方法不能带有主体
/* public void fireCircle(){
System.out.println("钻火圈");
}*/
//接口中的方法有默认修饰符 public abstract 但是建议自己写上 void fireCircle(); public abstract void fun(); public default void aaa(){ System.out.println("接口默认方法"); } public static void bbb(){ System.out.println("接口静态方法"); }
}
class Snake implements AniamlInterface{
@Override public void fireCircle() { System.out.println("bbb"); } @Override public void fun() { System.out.println("aaa"); } public void show(){ System.out.println("adf"); }
}: