houjiheng-java-day06
2021/7/29 14:35:48
本文主要是介绍houjiheng-java-day06,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
抽象类
- 概述: 使用abstract关键字修饰的类就是抽象类
- 特点: 这种类不能被创建对象,它就是用来做父类的,被子类继承的
格式
修饰符 abstract class 类名{ }
抽象类中的成员
- 成员变量
- 成员方法
- 构造方法
- 抽象方法
抽象方法: 没有方法体,使用abstract修饰的方法就是抽象方法
修饰符 abstract 返回值类型 方法名(形参列表); 例如: public abstract void work();
抽象方法的作用: 强制要求子类重写的
- 抽象方法: 没有方法体,使用abstract修饰的方法就是抽象方法
- 抽象方法定义格式: 修饰符 abstract 返回值类型 方法名(形参列表);
- 使用场景:如果父类中某个方法,所有子类都有不同的实现,那么就可以把该方法定义为抽象方法
- 抽象方法的作用: 强制要求子类重写
package com.company.day06.chouxianglei; // 抽象类 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 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; } @Override public String toString() { return "Animal{" + "name='" + name + '\'' + ", age=" + age + '}'; } } public class Dog extends Animal{ @Override public void eat() { System.out.println("狗狗吃肉"); } } public class Cat extends Animal { @Override public void eat() { System.out.println("猫吃鱼"); } } public class Test { public static void main(String[] args) { Cat cat = new Cat(); cat.eat(); Dog dog = new Dog(); dog.eat(); } }
抽象类的注意事项
- 抽象类不能被创建对象,就是用来做“父类”,被子类继承的。
- 抽象类不能被创建对象,但可以有“构造方法”——为成员变量初始化。
- 抽象类中可以没有抽象方法,但抽象方法必须定义在抽象类中
- 子类继承抽象类后,必须重写抽象类中所有的抽象方法,否则子类必须也是一个抽象类
匿名类
new Animal() { @Override public void eat() { System.out.println("匿名动物吃"); } }.eat();
模板设计模式
设计模式就是解决一些问题时的固定思路,也就是代码设计思路经验的总结。
针对某些情况,在父类中指定一个模板,然后根据具体情况,在子类中灵活的具体实现该模板
public abstract class Person{ // 有方法体的方法: 通用模板 public void sleep(){ System.out.println("两眼一闭,就睡觉..."); } // 没有方法体的方法(抽象方法): 填充模板(要子类重新实现的) public abstract void eat(); }
抽象类体现的就是模板设计思想,模板是将通用的东西在抽象类中具体的实现,而模板中不能决定的东西定义成抽象方法,让使用模板(继承抽象类的类)的类去重写抽象方法实现需求
模板模式的实现步骤
- 定义抽象父类作为模板
- 在父类中定义"模板方法"— 实现方法(通用模板)+抽象方法(填充模板)
- 子类继承父类,重写抽象方法(填充父类的模板)
- 测试类: -创建子类对象,通过子类调用父类的“实现的方法”+ “子类重写后的方法”
案例
假如我现在需要定义新司机和老司机类,新司机和老司机都有开车功能,开车的步骤都一样,只是驾驶时的姿势有点不同,新司机:开门,点火,双手紧握方向盘,刹车,熄火,老司机:开门,点火,右手握方向盘左手抽烟,刹车,熄火。那么这个时候我们就可以将固定流程写到父类中,不同的地方就定义成抽象方法,让不同的子类去重写
分析:
- 司机类
- 开车方法: 确定实现–通用模板
- 开门
- 点火
- (姿势)
- 刹车
- 熄火
- 姿势方法: 不确定实现–填充模板
- 开车方法: 确定实现–通用模板
- 新司机类继承司机类,重写姿势方法
- 老司机类继承司机类,重写姿势方法
public abstract class Driver { // 开车方法 通用模板 public void driveCar(){ System.out.println("开门"); System.out.println("点火"); // 姿势?? ziShi(); System.out.println("刹车"); System.out.println("熄火"); } // 姿势方法 填充模板 public abstract void ziShi(); } public class NewDriver extends Driver{ @Override public void ziShi() { System.out.println("双手紧握方向盘"); } } public class OldDriver extends Driver{ @Override public void ziShi() { System.out.println("右手握方向盘左手抽烟"); } } public class Test2 { public static void main(String[] args) { NewDriver newDriver = new NewDriver(); newDriver.driveCar(); OldDriver oldDriver = new OldDriver(); oldDriver.driveCar(); } }
final关键字
final关键字的概述
final: 不可改变。可以用于修饰类、方法和变量。
- 类:被修饰的类,不能被继承 比如String。
- 方法:被修饰的方法,不能被重写。
- 变量:被修饰的变量,就只能赋值一次,不能被重新赋值。
修饰类
修饰符 final class 类名 { } 例如: public final class FinalClassFu { } public class FinalClassZi /*extends FinalClassFu*/ { // FinalClassFu类被final修饰了,所以不能被继承 }
查询API发现像 public final class String 、public final class Math 、public final class Scanner 等,很多我们学习过的类,都是被final修饰的,目的就是供我们使用,而不让我们所以改变其内容。
修饰方法
修饰符 final 返回值类型 方法名(参数列表){ //方法体 }
重写被 final修饰的方法,编译时就会报错。
public class FinalMethodFu { public final void show(){ } } public class FinalMethodZi extends FinalMethodFu { /*@Override public void show() { }*/ // 无法重写父类中的show方法,因为父类中的show方法被final修饰了 }
修饰变量
局部变量——基本类型
基本类型的局部变量,被final修饰后,只能赋值一次,不能再更改。代码如下:
final int NUM = 10; NUM = 220; // 报错
局部变量——引用类型
引用类型的局部变量,被final修饰后,只能指向一个对象,地址不能再更改。但是不影响对象内部的成员变量值的修改,代码如下:
public class Test3 { public static void main(String[] args) { final Student student1 = new Student("eric", 11); System.out.println(student1); // student1 = new Student("bob", 20); 不能有新的指向 student1.setAge(30); System.out.println(student1.getAge()); System.out.println(student1); } }
成员变量涉及到初始化的问题,初始化方式有两种,只能二选一:
public class FinalVariable { final int NUM1 = 10; }
public class FinalVariable { final int NUM2; public FinalVariable(int NUM2){ this.NUM2 = NUM2; } public FinalVariable(){ this.NUM2 = 10; } }
被final修饰的常量名称,一般都有书写规范,所有字母都大写
- final修饰类,类不能被继承。
- final修饰方法,方法不能被重写。
- final修饰变量,变量不能被改值,只能赋值一次.
static关键字
static是一个静态修饰符关键字,表示静态的意思,可以修饰成员变量和成员方法以及代码块。
static修饰成员变量
当 static 修饰成员变量时,该变量称为类变量。该类的每个对象都共享同一个类变量的值。任何对象都可以更改该类变量的值,但也可以在不创建该类的对象的情况下对类变量进行操作
static 数据类型 变量名; // 调用 对象名.静态成员变量名; 不推荐 类名.静态成员变量名; 推荐
public class Person { String name; static int id; public Person(String name) { this.name = name; ++id; } public static void main(String[] args) { System.out.println(Person.id); Person p1 = new Person("张三"); Person p2 = new Person(";李四"); Person p3 = new Person(";李四"); System.out.println(Person.id); //3 System.out.println(p3.id); } }
静成员会随着类的加载而加载, 并且只加载一次, 会加载到静态区
static修饰成员方法
被static修饰的方法会变成静态方法,也称为类方法,该静态方法可以使用类名直接调用。
修饰符 static 返回值类型 方法名 (参数列表){ // 执行语句 } 访问 对象名.方法名(实参); 类名.方法名(实参); 推荐
package com.company.day06.chouxianglei; import java.util.Arrays; public class Person { String name; static int id; public Person(String name) { this.name = name; ++id; } public static void m1(){ System.out.println("m1()"); } public static void main(String[] args) { Person p1 = new Person("张三"); p1.m1(); Person.m1(); int arr[] = {111, 223, 444}; System.out.println(Arrays.toString(arr)); } }
静态方法调用的注意事项:
- 静态方法中不能出现this关键字
- 静态方法中只能直接访问静态成员变量和静态成员方法
- 静态方法中不能直接访问非静态成员变量和非静态成员方法
- 非静态方法中可以直接访问一切成员变量和成员方法
public class Person { String name; static int id; public Person(String name) { this.name = name; ++id; } public void m2(){ this.name = "haha"; id = 100; } public static void m1(){ // this.name 错 // name = "" 错 id = 100; }
以后开发中static的应用
概述
以后的项目中,通常会需要一些“全局变量”或者“全局的工具方法”,这些全局变量和方法,可以单独定义在一个类中,并声明为static(静态)的,可以很方便的通过类名访问
package com.company.day06.utils; public class Utils { // 静态代码块, 优先于main方法执行 static { AGE = 10; } public static int AGE; // "全局变量" public static final int WIDTH = 800; public static final int HEIGHT = 800; // "全局方法" // 找int数组中的最大值 public static int getArrayMax(int[] arr){ int max = arr[0]; for (int i = 0; i < arr.length; i++) { if(arr[i] > max){ max = arr[i]; } } return max; } } import com.company.day06.utils.Utils; public class Test4 { public static void main(String[] args) { System.out.println(Utils.WIDTH); System.out.println(Utils.HEIGHT); int[] arr = {122, 334,444}; System.out.println(Utils.getArrayMax(arr)); System.out.println(Utils.AGE); } }
接口
- 引用数据类型除了类其实还有接口,接下来学习接口的概述
概述: 接口是Java语言中的一种引用类型,是方法的"集合",所以接口的内部主要就是定义方法,包含常量,抽象方法(JDK 7及以前),默认方法和静态方法(JDK 8),私有方法(jdk9)。
接口的定义,它与定义类方式相似,但是使用 interface 关键字。它也会被编译成.class文件,但一定要明确它并不是类,而是另外一种引用数据类型。
public class 类名{}–>.class
public interface 接口名{}->.class
引用数据类型:数组,类,接口
接口的使用,它不能创建对象,但是可以被实现(implements ,类似于被继承)。一个实现接口的类(可以看做是接口的子类),需要实现接口中所有的抽象方法,创建该类对象,就可以调用方法了,否则它必须是一个抽象类
格式
public interface 接口名称 { // 常量(jdk7及其以前) // 抽象方法(jdk7及其以前) // 默认方法(jdk8) // 静态方法(jdk8) // 私有方法(jdk9) }
package com.company.day06.jiekou; public interface IA { // 常量(jdk7及其以前) 使用public static final关键字修饰,这三个关键字都可以省略 public static final int NUM = 10; // 抽象方法(jdk7及其以前) 使用public abstract关键字修饰,这2个关键字都可以省略 public abstract void method1(); void method2(); // 默认方法(jdk8) 使用public default关键字修饰,public可以省略,default不可以省略 public default void method3(){ System.out.println("默认方法"); } // 静态方法(jdk8) 使用public static关键字修饰,public可以省略,static不可以省略 public static void method4(){ System.out.println("静态方法"); } // 私有方法(jdk9) 使用private关键字修饰,private不可以省略 private void method5(){ System.out.println("method5"); } private static void method6(){ System.out.println("method6"); } }
实现接口
类与接口的关系为实现关系,即类实现接口,该类可以称为接口的实现类,也可以称为接口的子类。实现的动作类似继承,格式相仿,只是关键字不同,实现使用 implements关键字。
public class ZI implements IA, IB{ @Override public void method1() { } @Override public void method2() { } @Override public void show() { } }
接口中成员的访问特点:
- 接口中的常量: 主要是供接口直接使用
- 接口中的抽象方法: 供实现类重写的
- 接口中的默认方法: 供实现类继承的(实现类中可以直接调用,实现类对象也可以直接调用)
- 接口中的静态方法: 只供接口直接调用,实现类继承不了
- 接口中的私有方法: 只能在接口中直接调用,实现类继承不了
多实现时的几种冲突情况
- 公有静态常量的冲突
- 公有抽象方法的冲突
- 公有默认方法的冲突
- 公有静态方法的冲突
- 私有方法的冲突
公有静态常量的冲突
public interface A { public static final int NUM1 = 10; } public interface B { public static final int NUM1 = 20; public static final int NUM2 = 30; } public class Impl implements A, B{ public static void main(String[] args) { // 公有静态常量的冲突: 如果多个接口中有相同的常量,那么实现类就无法继承 // System.out.println(Impl.NUM1); // 报错 System.out.println(Impl.NUM2); } }
公有抽象方法的冲突
实现类只需要重写一个
public interface A { public static final int NUM1 = 10; public abstract void method(); } public interface B { public static final int NUM1 = 20; public static final int NUM2 = 30; public abstract void method(); } public class Impl implements A, B{ public static void main(String[] args) { // 公有静态常量的冲突: 如果多个接口中有相同的常量,那么实现类就无法继承 // System.out.println(Impl.NUM1); // 报错 System.out.println(Impl.NUM2); } @Override public void method() { System.out.println("重写"); } }
公有默认方法的冲突
- 实现类必须重写一次最终版本
public interface A { public static final int NUM1 = 10; public abstract void method(); public default void method2(){ System.out.println("A 接口的默认方法method2"); } } public interface B { public static final int NUM1 = 20; public static final int NUM2 = 30; public abstract void method(); public default void method2(){ System.out.println("B 接口的默认方法method2"); } } public class Impl implements A, B{ @Override public void method() { System.out.println("重写"); } @Override public void method2() { B.super.method2(); } public static void main(String[] args) { Impl impl = new Impl(); impl.method2(); } }
公有静态方法的冲突:
静态方法是直接属于接口的,不能被继承,所以不存在冲突
私有方法的冲突
- 私有方法只能在本接口中直接使用,不存在冲突
抽象类和接口的练习
通过实例进行分析和代码演示抽象类和接口的用法。
1、举例:
犬: —抽象父类
行为:吼叫;吃饭;
缉毒犬:继承犬类,实现缉毒接口
行为:吼叫;吃饭;缉毒;
缉毒接口:
缉毒
- 如果一个父类中的某个方法,所有子类都有不同的实现,那么该方法就应该定义成抽象方法,所以该父类就是抽象类 (父类一般都是抽象类)
- 如果某个功能是一个类额外增加的,那么就可以把这个额外的功能定义到接口中,再这个类去实现
分析:
由于犬分为很多种类,他们吼叫和吃饭的方式不一样,在描述的时候不能具体化,也就是吼叫和吃饭的行为不能明确。当描述行为时,行为的具体动作不能明确,这时,可以将这个行为写为抽象行为,那么这个类也就是抽象类。
可是有的犬还有其他额外功能,而这个功能并不在这个事物的体系中 , 例如 : 缉毒犬。缉毒的这个功能有好多种动物都有 , 例如 : 缉毒猪 , 缉毒鼠。我们可以将这个额外功能定义接口中 ,让缉毒犬继承犬且实现缉毒接口 , 这样缉毒犬既具备犬科自身特点也有缉毒功能。
- 额外的功能—> 在接口中定义,让实现类实现
- 共性的功能—> 在父类中定义,让子类继承
public interface JiDu { public abstract void jiDu(); } public abstract class Dog { public abstract void houJiao(); public abstract void eat(); } public class JiDuDog extends Dog implements JiDu{ @Override public void houJiao() { System.out.println("缉毒犬找到了毒品,开始吼叫,汪汪汪...."); } @Override public void eat() { System.out.println("缉毒之前,开始吃骨头..."); } @Override public void jiDu() { System.out.println("吃完东西后,开始使用鼻子查找毒品...."); } } public class Test { public static void main(String[] args) { JiDuDog jiDuDog = new JiDuDog(); jiDuDog.eat(); jiDuDog.jiDu(); jiDuDog.houJiao(); } }
这篇关于houjiheng-java-day06的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-27数据结构与算法面试题详解及练习
- 2024-12-27网络请求面试题详解与实战
- 2024-12-27数据结构和算法面试真题详解与实战教程
- 2024-12-27网络请求面试真题解析与实战教程
- 2024-12-27数据结构和算法大厂面试真题详解与实战指南
- 2024-12-27TS大厂面试真题解析与应对策略
- 2024-12-27TS大厂面试真题详解与解析
- 2024-12-27网站安全入门:如何识别和修复漏洞
- 2024-12-27SQL注入基础教程
- 2024-12-27初学者指南:理解和修复跨域漏洞