抽象类,抽象方法
抽象方法:
定义格式
注意事项:
构造方法的作用:
当创建子类对象时给属性赋值。
public abstract class Person {
//添加属性
private String name;
private int age;
//设置构造函数用于为子类的属性添加数据
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//get set用于给子类操作属性
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 abstract void work();
}
package Demo.Demo1;
public class student extends Person{
public student() {
}
public student(String name, int age) {
super(name, age);
}
@Override
public void work() {
System.out.println("学生的工作是学生");
}
}
package Demo.Demo1;
public class Test {
public static void main(String[] args) {
student s = new student("zhangsan",20);
s.work();
System.out.println(s.getName());
}
}
抽象类练习一:
package Demo.Demo2;
public abstract class Animal {
private String name;
private int age;
public Animal() {
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public abstract void eat();
public void drink(){
System.out.println("喝水");
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Animal{name = " + name + ", age = " + age + "}";
}
}
package Demo.Demo2;
public class frog extends Animal{
public frog() {
}
public frog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("吃虫子");
}
}
package Demo.Demo2;
public class Dog extends Animal{
public Dog() {
}
public Dog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("吃骨头");
}
}
package Demo.Demo2;
public class Sheep extends Animal{
public Sheep() {
}
public Sheep(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("吃草");
}
}
package Demo.Demo2;
public class Test {
public static void main(String[] args) {
frog f = new frog("小黄",1);
System.out.println(f.getName()+", "+f.getAge());
f.eat();
f.drink();
}
}
抽象类的总结:
接口
为什么有接口
接口的理解:
接口不是一种事物他是对行为的抽象是一种规则。
接口的定义与使用
接口练习一:
package Demo.Demo3;
public abstract class Animal {
private String name;
private int age;
public Animal() {
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public abstract void eat();
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Animal{name = " + name + ", age = " + age + "}";
}
}
package Demo.Demo3;
public class Dog extends Animal implements swimming {
public Dog() {
}
public Dog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("吃骨头");
}
@Override
public void swim() {
System.out.println("狗在游泳");
}
}
//兔子不会游泳没有连接接口
package Demo.Demo3;
public class rabit extends Animal {
public rabit() {
}
public rabit(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("吃草");
}
}
package Demo.Demo3;
public class frog extends Animal implements swimming{
public frog() {
}
public frog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("吃虫子");
}
@Override
public void swim() {
System.out.println("青蛙在游泳");
}
}
package Demo.Demo3;
public class Test {
public static void main(String[] args) {
frog f = new frog("小黄",1);
System.out.println(f.getName()+", "+f.getAge());
f.eat();
f.swim();
}
}
接口中成员的特点
接口和类之间的关系
接口练习一(Demo5)
package Demo.Demo5;
//将人写为抽象的,用于拒绝外界创建该对象
public abstract class Person {
private String name;
private int 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 Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
//运动员类
package Demo.Demo5;
public abstract class jock extends Person {
public jock() {
}
public jock(String name, int age) {
super(name, age);
}
//运动员
//打球的抽象方法
public abstract void work();
}
package Demo.Demo5;
public abstract class instructor extends Person{
public instructor() {
}
public instructor(String name, int age) {
super(name, age);
}
//教练
public abstract void techer();
}
//说英语的接口
public interface english {
public abstract void lean();
}
//篮球教练
package Demo.Demo5;
public class basketball_ins extends instructor{
public basketball_ins() {
}
public basketball_ins(String name, int age) {
super(name, age);
}
@Override
public void techer() {
System.out.println("篮球教练教篮球");
}
}
//篮球运动员
package Demo.Demo5;
public class basketball_player extends jock{
public basketball_player() {
}
public basketball_player(String name, int age) {
super(name, age);
}
@Override
public void work() {
System.out.println("篮球运动员打篮球");
}
}
//乒乓球教练
package Demo.Demo5;
public class table_tennis_ins extends instructor implements english{
public table_tennis_ins() {
}
public table_tennis_ins(String name, int age) {
super(name, age);
}
@Override
public void techer() {
System.out.println("乒乓球教练教篮球");
}
@Override
public void lean() {
System.out.println("乒乓球教练学英语");
}
}
//乒乓球运动员
package Demo.Demo5;
public class table_tennis_player extends jock implements english{
public table_tennis_player() {
}
public table_tennis_player(String name, int age) {
super(name, age);
}
@Override
public void lean() {
System.out.println("乒乓球运动员学英语");
}
@Override
public void work() {
System.out.println("乒乓球运动员打乒乓球");
}
}
package Demo.Demo5;
public class Test {
public static void main(String[] args) {
table_tennis_player t = new table_tennis_player("wdwd",20);
t.lean();
t.work();
System.out.println(t.getName()+","+t.getAge());
System.out.println("===================================");
basketball_ins b = new basketball_ins("ww",30);
b.techer();
System.out.println(b.getName()+","+b.getAge());
}
}
JDK8开始接口中新增的方法
jdk7之前的问题:只要接口发生变化则实现类也必须进行更改否则就会报错。
有方法体的接口为了接口升级时有兼容性所采取的,接口修改后不需要立马修改,等以后用到哪个规则在进行重写。
JDK8后接口新增的方法
package Demo.Demo6;
public interface inxertA {
void show1();
default void show2(){
System.out.println("接口中的默认方法");
}
public default void show3(){
System.out.println("inxertA中的默认方法");
}
}
//接口的重名默认方法
package Demo.Demo6;
public interface inxertB {
public default void show3(){
System.out.println("inxertB中的默认方法");
}
}
package Demo.Demo6;
public class InImpl implements inxertA,inxertB{
@Override
public void show1() {
System.out.println("接口中的抽象方法重写");
}
//两个接口中的同名默认方法必须要重新写
@Override
public void show3() {
System.out.println("同名默认方法必须要重新写");
}
@Override
public void show2() {
System.out.println("默认方法重写");
}
}
package Demo.Demo6;
public class Test {
public static void main(String[] args) {
InImpl ii = new InImpl();
ii.show1();
ii.show2();
ii.show3();
}
}
package Demo.Demo7;
public interface interfice {
//设一个静态方法
public static void show(){
System.out.println("接口中的静态方法,无法被重写");
}
//抽象方法
public abstract void demo();
}
package Demo.Demo7;
public class interImpl implements interfice{
@Override
public void demo() {
System.out.println("抽象方法重写");
}
//写一个静态方法(只是和接口中的静态方法刚好重名,不是重写),只有虚方法表中的才能重写,静态方法不在虚方法表。
public static void show(){
System.out.println("只是和接口中的静态方法刚好重名,不是重写");
}
}
package Demo.Demo7;
public class Test {
public static void main(String[] args) {
interfice.show();
interImpl.show();
interImpl ii = new interImpl();
ii.demo();
}
}
JDK9以后得新增的方法
package Demo.Demo8;
public interface interA {
public default void show1(){
System.out.println("show1方法开始执行");
show3();
}
public default void show2(){
System.out.println("show2方法开始执行");
show3();
}
public static void show5(){
System.out.println("show5静态方法开始执行");
show4();
}
//普通的私有方法,给默认方法服务
private void show3(){
System.out.println("记录运行中的各种细节");
}
//静态的私有方法,给静态方法服务
private static void show4(){
System.out.println("记录运行中的各种细节");
}
}
新增方法总结:
接口的应用
设计模式
适配器设计模式
内部类
什么是内部类
内部类的应用场景,小结
成员内部类
内部类的分类
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
前三个了解即可,匿名内部类着重掌握。
成员内部类的书写要求
创建成员内部类的对象
package Demo.Demo10;
public class Outer {
String name;
//如何在私有下获取内部类的对象
private class Inner{
}
// 创建一个方法用于返回内部类的对象
public Inner getInstance(){
return new Inner();
}
}
package Demo.Demo10;
public class Test {
public static void main(String[] args) {
//创建内部类的对象
// Outer.Inner i = new Outer(). new Inner();
//内部类私有下获取对象
Outer o = new Outer();
//因为Inner为私有所以Outer.Inner会报错
// Outer.Inner instance = o.getInstance();
//解决方案
//1.使用Inner的父类去接收(即多态)
Object instance = o.getInstance();
//2.不使用对象接受而直接使用对象(链式编程)
System.out.println(o.getInstance());
}
}
成员内部类练习一:
package Test.Test1;
public class Outer {
private int a = 10;
class Inner{
private int a = 20;
public void show(){
int a = 30;
//获取了外部类对象的地址值
System.out.println(Outer.this.a);//10
System.out.println(this.a);//20
System.out.println(a);//30
}
}
}
package Test.Test1;
public class test {
public static void main(String[] args) {
Outer.Inner oi = new Outer().new Inner();
oi.show();
}
}
有内部类的内存图解释
内部类的内存图
内部类和外部类在内存中为独立的字节码文件。
成员内部类小结
静态内部类
package Demo.Demo11;
public class Outer {
// int a = 10;
// static int b = 20;
static class Inner{
public void show1(){
System.out.println("非静态方法被调用");
// //要调用非静态的属性就要先创建对象
// Outer o = new Outer();
// System.out.println(o.a);
// System.out.println(b);
}
public static void show2(){
System.out.println("静态方法被调用");
// //要调用非静态的属性就要先创建对象
// Outer o = new Outer();
// System.out.println(o.a);
// System.out.println(b);
}
}
}
package Demo.Demo11;
public class Test {
public static void main(String[] args) {
//调用静态内部类的非静态方法
Outer.Inner inner = new Outer.Inner();
inner.show1();
//调用静态内部类的静态方法
//不推荐
// inner.show2();
//推荐
Outer.Inner.show2();
}
}
静态内部类总结
局部内部类
package Demo.Demo12;
public class Outer {
int a = 10;
public void show(){
int b = 20;
//定义局部内部类
class Inner{
int c = 30;
public void show2(){
System.out.println(a);
System.out.println(b);
System.out.println("局部内部类的非静态方法");
}
public static void show3(){
System.out.println("局部内部类的静态方法");
}
}
//在方法中访问内部类
Inner i = new Inner();
System.out.println(i.c);
i.show2();
Inner.show3();
}
}
package Demo.Demo12;
public class Test {
public static void main(String[] args) {
Outer o = new Outer();
o.show();
}
}
匿名内部类
package Demo.Demo13;
public abstract class Swim {
public abstract void swim();
}
package Demo.Demo13;
public class Animal {
public void eat(){
System.out.println("继承类中的父类");
}
}
package Demo.Demo13;
public class Test {
public static void main(String[] args) {
new Swim(){
@Override
public void swim() {
System.out.println("匿名内部类的重写");
}
};
new Animal(){
@Override
public void eat() {
System.out.println("重写继承类的方法");
}
};
//应用场景,直接在方法中写匿名内部类,将其赋值个静态方法(赋值的对象为匿名
// 内部类所创建的Animal的子类的对象)
method(
new Animal(){
@Override
public void eat() {
System.out.println("重写后的被匿名内部类调用的方法");
}
}
);
}
//写一个静态方法来调用父类的对象
public static void method(Animal a){
a.eat();
}
}
public class Test2 {
public static void main(String[] args) {
//将匿名内部类赋值给一个Swim对象
Swim s = new Swim(){
@Override
public void swim() {
System.out.println("重写后的游泳方法");
}
};
s.swim();
//将匿名内部类看做一个对象,直接调用方法
new Swim(){
@Override
public void swim() {
System.out.println("重写后的游泳方法2");
}
}.swim();
}
}
//运行结果
重写后的游泳方法
重写后的游泳方法2
匿名内部类总结
课后练习题
第一题
第一题:
需求:
分析以下需求用代码实现:
定义形状类:
功能:求面积,求周长
定义圆形类Round:
属性:半径,圆周率
功能:求面积,求周长
定义长方形类Rectangle:
属性:长和宽功能:求面积,求周长
定义测试类:
分别创建圆形和长方形对象,为相应的属性赋值分别调用求面积和求周长的方法
答案
设置接口定义周长和面积两个方法
package Work.Work1;
public interface shape {
//设置面积和周长两种方法
//周长
public double circumference();
//面积
public double area();
}
圆的实现类实现了shape接口中的两个方法
package Work.Work1;
public class Round implements shape {
private double r;
private static final double pr = 3.1415926;
public Round() {
}
public Round(double r) {
this.r = r;
}
/**
* 获取
* @return r
*/
public double getR() {
return r;
}
/**
* 设置
* @param r
*/
public void setR(double r) {
this.r = r;
}
public String toString() {
return "Round{r = " + r + ", pr = " + pr + "}";
}
//周长的方法
@Override
public double circumference() {
double lenght = 2*pr*r;
return lenght;
}
//获取面积的方法
@Override
public double area() {
double area = pr*r*r;
return area;
}
}
长方形的实现类
package Work.Work1;
public class Rectangle implements shape {
private double longht;
private double wide;
public Rectangle() {
}
public Rectangle(double longht, double wide) {
this.longht = longht;
this.wide = wide;
}
/**
* 获取
* @return longht
*/
public double getLonght() {
return longht;
}
/**
* 设置
* @param longht
*/
public void setLonght(double longht) {
this.longht = longht;
}
/**
* 获取
* @return wide
*/
public double getWide() {
return wide;
}
/**
* 设置
* @param wide
*/
public void setWide(double wide) {
this.wide = wide;
}
public String toString() {
return "Rectangle{longht = " + longht + ", wide = " + wide + "}";
}
//周长的方法
@Override
public double circumference() {
return (longht+wide)*2;
}
//获取面积的方法
@Override
public double area() {
return longht*wide;
}
}
Test测试类,用以测试代码是否正确
package Work.Work1;
public class Test {
public static void main(String[] args) {
Round r = new Round(3);
System.out.println("圆的周长为"+r.circumference());
System.out.println("圆的面积为"+r.area());
Rectangle re = new Rectangle(3,4);
System.out.println("长方形的周长为"+re.circumference());
System.out.println("长方形的面积为"+re.area());
}
}
第二题
第二题:
需求:
定义手机类
行为:打电话,发短信
定义接口IPlay
行为:玩游戏
定义旧手机类继承手机类
行为:继承父类的行为
定义新手机继承手机类实现IPlay接口
行为:继承父类的行为,重写玩游戏方法
定义测试类
在测试类中定义一个 用手机的方法,要求该方法既能接收老手机对象,也能接收新手机对象
在该方法内部调用打电话,发短信以及新手机特有的玩游戏方法
定义一个Phone的抽象类,用于存储方法
package Work.Work2;
public abstract class Phone {
//定义手机抽象类
abstract void Call();
abstract void Texting();
}
定义Iplay接口
package Work.Work2;
//定义接口
public interface IPlay {
abstract void playgame();
}
两个实现类
package Work.Work2;
public class OldPhone extends Phone{
@Override
void Call() {
System.out.println("旧手机在打电话");
}
@Override
void Texting() {
System.out.println("旧手机在发消息");
}
}
package Work.Work2;
public class NewPhone extends Phone implements IPlay{
@Override
public void playgame() {
System.out.println("新手机在玩游戏");
}
@Override
void Call() {
System.out.println("新手机在打电话");
}
@Override
void Texting() {
System.out.println("新手机在发消息");
}
}
测试类(重要,第一时间没做出来)
package Work.Work2;
public class Test {
public static void main(String[] args) {
OldPhone op = new OldPhone();
NewPhone np = new NewPhone();
Test t = new Test();
t.use(op);
t.use(np);
}
//创建一个方法用于实现要求
public void use(Phone phone){
phone.Call();
phone.Texting();
// phone.playgame();
//判断是否为Iplay的实例,是则执行
if (phone instanceof IPlay){
((IPlay) phone).playgame();
}
}
}
第三题
第三题:
需求:
接口IPlay中有一个方法playGame(),在测试类中如何调用该方法?
要求1.创建子类实现接口的方式实现 要求2:用匿名内部类实现
一个抽象类Fun中有一个抽象方法 fun() , 在测试类中如何调用该方法?
要求1.创建子类继承抽象类的方式实现 要求2:用匿名内部类实现
答案
一小问:
package Work.Work3;
public interface Iplay {
void playGame();
}
package Work.Work3;
public class IplayImpl implements Iplay{
@Override
public void playGame() {
System.out.println("创建子类实现playGame方法");
}
}
package Work.Work3;
public class Test1 {
public static void main(String[] args) {
//使用子类实现
IplayImpl ii = new IplayImpl();
ii.playGame();
//使用匿名内部类实现
new Iplay(){
@Override
public void playGame() {
System.out.println("使用匿名内部类实现");
}
}.playGame();
}
}
第二小问:
package Work.Work3;
public abstract class Fun {
abstract void fun();
}
package Work.Work3;
public class FunImpl extends Fun{
@Override
void fun() {
System.out.println("创建子类实现fun方法");
}
}
package Work.Work3;
public class Test2 {
public static void main(String[] args) {
//使用子类实现
FunImpl fi = new FunImpl();
fi.fun();
//使用匿名内部类实现
new Fun(){
@Override
void fun() {
System.out.println("使用匿名内部类实现");
}
}.fun();
}
}
第四题
第四题:
需求:
在控制台输出”HelloWorld”
自己书写,不要用idea自动生成。
interface Inter { void show(); } class Outer { //补齐代码 } public class OuterDemo { public static void main(String[] args) { Outer.method().show(); } }
答案
为ChatGPT给出(自己的实现方式不太正确,与本课教学不同):
package Work.Work4.wd;
interface Inter {
void show();
}
class Outer {
//补齐代码
//创建静态方法
public static Inter method(){
//使用匿名内部类
return new Inter(){
@Override
public void show() {
System.out.println("HelloWorld");
}
};
}
}
public class OuterDemo {
public static void main(String[] args) {
Outer.method().show();
}
}
第五题
第五题:
需求:
在测试类Test中创建A的对象a并调用成员方法methodA(),要求用两种方式实现
自己书写,不要用idea自动生成。
public class Test { public static void main(String[] args) { } } //定义接口 interface InterA { void showA(); } class A { public void methodA(InterA a) { a.showA(); } }
答案:
不知道对不对。
package Work.Work5;
public class Test {
public static void main(String[] args) {
A a = new A();
a.methodA(
new InterA() {
@Override
public void showA() {
System.out.println("showA1");
}
}
);
//第二种
new A().methodA(
new InterA() {
@Override
public void showA() {
System.out.println("showA2");
}
}
);
}
}
//定义接口
interface InterA {
void showA();
}
class A {
public void methodA(InterA a) {
a.showA();
}
}
第六题
第六题:
需求:
在测试类Test中创建B的对象b,并调用成员方法methodB
自己书写,不要用idea自动生成。
public class Test { public static void main(String[] args) { } } //定义一个接口 interface InterB { void showB(); } //目标:调用成员方法methodB class B { InterB b; public B(InterB b){ this.b = b; } public void methodB(){ b.showB(); } }
答案
package Work.Work6;
public class Test {
public static void main(String[] args) {
B b = new B(
new InterB() {
@Override
public void showB() {
System.out.println("调用了showB");
}
}
);
b.methodB();
}
}
//定义一个接口
interface InterB {
void showB();
}
//目标:调用成员方法methodB
class B {
InterB b;
public B(InterB b){
this.b = b;
}
public void methodB(){
b.showB();
}
}