修饰符 abstract class 类名{ }
抽象类中的成员
抽象方法: 没有方法体,使用abstract修饰的方法就是抽象方法
修饰符 abstract 返回值类型 方法名(形参列表); 例如: public abstract void work();
抽象方法的作用: 强制要求子类重写的
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 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修饰的常量名称,一般都有书写规范,所有字母都大写
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 返回值类型 方法名 (参数列表){ // 执行语句 } 访问 对象名.方法名(实参); 类名.方法名(实参); 推荐
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)); } }
静态方法调用的注意事项:
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(); } }