
本文共 14993 字,大约阅读时间需要 49 分钟。
第一阶段模块二笔记
面向对象编程的概念
- 万物皆对象。
- 面向对象指以属性和行为的观点去分析现实生活中的事物。
- 理解面向对象的思想精髓:封装、继承、多态
类和对象的概念
- 对象主要指现实生活中客观存在的实体,在Java语言中体现为内存空间中的一块存储区域(堆区)。
- 类简单来就是“分类” ,是对具有相同特征和行为的多个对象共性的抽象描述,在Java语言中体现为一种引用数据类型,里面包含了描述特征/属性的成员变量以及描述行为的成员方法。
- 类是用于构建对象的模板,对象的数据结构由定义它的类来决定。
引用的定义
-
使用引用数据类型定义的变量叫做引用型变量,简称为"引用" 。
-
引用变量主要用于记录对象在堆区中的内存地址信息,便于下次访问。
成员变量的默认初始值
- 数值类型 byte、short、int、long、float、double、char :0
- boolean型:false
- 引用数据类型(非8种基本数据类型):null
可变长参数
-
返回值类型 方法名(参数的类型… 参数名)
-
方法参数部分指定类型的参数个数是可以改变的,也就是0~n个 。
-
一个方法的形参列表中最多只能声明一个可变长形参,并且需要放到参数列表的末尾。
// 自定义成员方法实现可变长参数的使用 看作一维数组使用 0 ~ n个 void showArgument(int num, String... args) { System.out.println("num = " + num); for(int i = 0; i < args.length; i++) { System.out.println("第" + (i+1) + "个参数为:" + args[i]); } }// 通过成员方法实现可变长参数的打印 p.showArgument(0); // num = 0 p.showArgument(1, "参数1"); // num = 1 // 第1个参数为:参数1 p.showArgument(2, "参数1", "参数2"); // num = 2 // 第1个参数为:参数1 // 第2个参数为:参数2
参数传递的注意事项
-
基本数据类型的变量作为方法的参数传递时,形参变量数值的改变通常不会影响到实参变量的数值,因为两个变量有各自独立的内存空间;
void show1(int ia) { ia = 200; // 200把ib传进来的10覆盖 System.out.println("show方法中:ia = " + ia); // 200 }public static void main(String[] args) { // 声明ArgumentTest类型的引用指向该类型的对象 ArgumentTest at = new ArgumentTest(); int ib = 10; at.show1(ib); System.out.println("main方法中:ib = " + ib); // 10 }
-
引用数据类型的变量作为方法的参数传递时,形参变量指向内容的改变会影响到实参变量指向内容的数值,因为两个变量指向同一块内存空间;
void show2(int[] arr1) { arr1[0] = 200; // 新增 10->200 System.out.println("show方法中:arr1[0] = " + arr1[0]); // 10 200 }public static void main(String[] args) { ArgumentTest at = new ArgumentTest(); int[] arr2 = new int[]{ 10, 20}; at.show2(arr2); System.out.println("main方法中:arr2[0] = " + arr2[0]); // 10 200 }
-
当引用数据类型的变量作为方法的参数传递时,若形参变量改变指向后再改变指定的内容,则通常不会影响到实参变量指向内容的改变,因为两个变量指向不同的内存空间。
void show2(int[] arr1) { arr1 = new int[2]; // 加上改行代码后,相当于在堆区中又重新申请一块内存空间 arr1[0] = 200; System.out.println("show方法中:arr1[0] = " + arr1[0]); // 10 200 200 }public static void main(String[] args) { ArgumentTest at = new ArgumentTest(); int[] arr2 = new int[]{ 10, 20}; at.show2(arr2); System.out.println("main方法中:arr2[0] = " + arr2[0]); // 10 200 10 }
内存结构之栈区
-
栈用于存放程序运行过程当中所有的局部变量。
一个运行的Java程序从开始到结束会有多次方法的调用。
-
JVM为每一个方法的调用在栈中分配一个对应的空间,这个空间称为该方法的栈帧(上图蓝色框)。
一个栈帧对应一个正在调用中的方法,栈帧中存储了该方法的参数、局部变量等数据。
-
当某一个方法调用完成后,其对应的栈帧将被清除。
构造方法
- 构造方法名与类名完全相同并且没有返回值类型,连void都不许有。
默认构造方法
- 当一个类中没有定义任何构造方法时,编译器会自动添加一个无参空构造构造方法,叫做默认/缺省构造方法,如:Person(){}
- 若类中出现了构造方法,则编译器不再提供任何形式的构造方法。
构造方法的作用
- 使用new关键字创建对象时会自动调用(无须引用调用)构造方法实现成员变量初始化工作。
方法重载
- 若方法名称相同,参数列表不同,这样的方法之间构成重载关系 (Overload)。
- 方法重载的主要形式体现在:参数的个数不同、参数的类型不同、参数的顺序不同,与返回值类型和形参变量名无关,但建议返回值类型最好相同。
- 判断方法能否构成重载的核心:调用方法时能否加以区分。
重载的实际意义
- 方法重载的实际意义在于调用者只需要记住一个方法名就可以调用各种不同的版本,来实现各种不同的功能。
this关键字
- 若在构造方法中出现了this关键字,则代表当前正在构造的对象。
- 若在成员方法中出现了this关键字,则代表当前正在调用的对象。
- this关键字本质上就是当前类类型的引用变量。
工作原理
-
在构造方法中和成员方法中访问成员变量时,编译器会加上this.的前缀,而this.相当于汉语中"我的",当不同的对象调用同一个方法时,由于调用方法的对象不同导致this关键字不同,从而this.方式访问的结果也就随之不同。
// 自定义成员方法实现所有特征的打印 隐含着this关键字,this关键字代表当前正在调用的对象 // Person this = p1; this.name = p1.name = 张飞 // Person this = p2; this.name = p2.name = 关羽 void show() { //System.out.println("我是" + this.name + ",今年" + this.age + "岁了!"); System.out.println("我是" + name + ",今年" + age + "岁了!"); }public static void main(String[] args) { Person p1 = new Person("张飞", 30); p1.show(); // 张飞 30 Person p2 = new Person("关羽", 35); p2.show(); // 关羽 35}
使用方式
-
当局部变量名与成员变量名相同时(提高代码可读性),在方法体中会优先使用局部变量(就近原则),若希望使用成员变量,则需要在成员变量的前面加上this.的前缀,明确要求该变量是成员变量。
public class Person { //不加this.关键字,成员变量还是默认值 String name; int age; // 就近原则 懒人原则 Person(String name, int age) { //不加this.关键字,局部变量自己给自己赋值,成员变量还是默认值 name = name; age = age; //在构造方法中出现了this关键字,则代表当前正在构造的对象,成员变量被初始化 this.name = name; this.age = age; }}
-
this关键字除了可以通过this.的方式调用成员变量和成员方法外,还可以作为方法的返回值。
// 自定义成员方法实现Person类型对象的获取并返回的行为 Person getPerson() { // 返回当前调用对象本身 Person tp = new Person(); return tp; return this; } public static void main(String[] args) { Person p4 = p1.getPerson(); System.out.println("p1 = " + p1); //我是张飞,今年34岁了! System.out.println("p4 = " + p4); //我是张飞,今年34岁了!}
-
在构造方法的第一行可以使用this()的方式来调用本类中的其它构造方法。
public class Boy { String name; Boy() { // 调用本类中的有参构造方法 this("无名"); //main函数入口 -> new boy()调用无参构造 -> this("无名");调用有参构造 -> 跳回无参构造方法 //执行结果: //有参构造方法! //无参构造方法! //我的名字是:无名 System.out.println("无参构造方法!"); } Boy(String name) { System.out.println("有参构造方法!"); this.name = name; } void show() { System.out.println("我的名字是:" + name); } public static void main(String[] args) { // 使用无参方式构造对象并打印特征 Boy b1 = new Boy(); b1.show(); // null // 使用有参方式构造对象并打印特征 Boy b2 = new Boy("张飞"); b2.show(); // 张飞 }
注意事项
-
引用类型变量用于存放对象的地址,可以给引用类型赋值为null,表示不指向任何对象。
-
当某个引用类型变量为null时无法对对象实施访问(因为它没有指向任何对象)。此时,如果通过引用访问成员变量或调用方法,会产生NullPointerException 异常。
Boy b3 = null; b3.show(); // 编译ok,运行会发生NullPointerException空指针异常
方法递归调用
-
递归本质就是指在方法体的内部直接或间接调用当前方法自身的形式。
//编程实现累乘积的计算并打印int show(int n) { // 递推 int num = 1; for(int i = 1; i <= n; i++) { num *= i; } return num;}int show(int n) { //递归 if(1 == n) return 1; return n*show(n-1); //不需要写else,因为上一行return把if语句结束了}
封装
- 通常情况下可以在测试类给成员变量赋值一些合法但不合理的数值,无论是编译阶段还是运行阶段都不会报错或者给出提示,此时与现实生活不符。
- 为了避免上述错误的发生,就需要对成员变量进行密封包装处理,来隐藏成员变量的细节以及保证成员变量数值的合理性,该机制就叫做封装。
封装的实现流程
- 私有化成员变量,使用private关键字修饰。
- private关键字修饰表示私有的含义,也就是该成员变量只能在当前类的内部使用
- 提供公有的get和set方法,并在方法体中进行合理值的判断。
- public关键字修饰表示公有的含义,也就是该方法可以在任意位置使用
- 在构造方法中调用set方法进行合理值的判断。
static关键字
- 使用static关键字修饰成员变量表示静态的含义,此时成员变量由对象层级提升为类层级,也就是整个类只有一份并被所有对象共享(修改一处,更新所有),该成员变量随着类的加载准备就绪,与是否创建对象无关。
- static关键字修饰的成员可以使用引用.的方式访问,但推荐**类名.**的方式。
使用方式
-
在非静态成员方法中既能访问非静态的成员又能访问静态的成员。 ( 静态成员被所有对象共享)
-
在静态成员方法中只能访问静态成员不能访问非静态成员。 ( 因为此时可能还没有创建对象)
-
在以后的开发中只有隶属于类层级并被所有对象共享的内容才可以使用 static关键字修饰。(不能滥用static关键字)
public class StaticTest { private int cnt = 1; // 隶属于对象层级,也就是每个对象都拥有独立的一份private static int snt = 2; // 隶属于类层级,也就是所有对象都共享同一份// 自定义非静态的成员方法 需要使用引用.的方式访问public void show() { System.out.println("cnt = " + this.cnt); // 1 System.out.println("snt = " + this.snt); // 2 静态成员被所有对象共享,this关键字可以省略}// 自定义静态的成员方法 推荐使用类名.的方式访问public static void test() { //System.out.println("cnt = " + cnt); // 报错 因为此时还没有创建对象 System.out.println("snt = " + snt); // 2 静态成员方法中没有this关键字,因为是可以通过类名.方式调用的}public static void main(String[] args) { StaticTest st = new StaticTest(); st.show(); // // 非静态的成员方法 需要使用引用.的方式访问 StaticTest.test(); // 静态的成员方法 推荐使用类名.的方式访问 }}
构造块和静态代码块(笔试)
- 构造块:在类体中直接使用{}括起来的代码块,每创建一个对象都会执行一次构造块。
- 静态代码块:使用static关键字修饰的构造块,静态代码块随着类加载时执行一次。
笔试考点
-
先执行父类的静态代码块,再执行子类的静态代码块。
-
执行父类的构造块,执行父类的构造方法体。
-
执行子类的构造块,执行子类的构造方法体。
public class BlockTest { // 当需要在执行构造方法体之前做一些准备工作时,则将准备工作的相关代码写在构造块中即可,比如:对成员变量进行的统一初始化操作 { System.out.println("构造块!"); // (2) } // 静态代码块会随着类的加载而准备就绪,会先于构造块执行 // 当需要在执行代码块之前随着类的加载做一些准备工作时,则编写代码到静态代码块中,比如:加载数据库的驱动包等 static { System.out.println("####静态代码块!"); // (1) } // 自定义构造方法 public BlockTest() { System.out.println("====构造方法体!"); // (3) } public static void main(String[] args) { BlockTest bt = new BlockTest(); BlockTest bt2 = new BlockTest(); }}
单例设计模式
- 在某些特殊场合中,一个类对外提供且只提供一个对象时(唯一,不管new几个都是它),这样的类叫做单例类,而设计单例的流程和思想叫做单例设计模式。
- 推荐饿汉式
实现流程
-
私有化构造方法,使用private关键字修饰。
-
声明本类类型的引用指向本类类型的对象,并使用private static关键字共同修饰。
-
提供公有的get方法负责将对象返回出去,并使用public static关键字共同修饰。
public class Singleton { // 2.声明本类类型的引用指向本类类型的对象,使用private static关键字共同修饰 //private static Singleton sin = new Singleton(); // 饿汉式(一回家就开吃) private static Singleton sin = null; // 懒汉式(饿的时候再吃) // 1.私有化构造方法,使用private关键字修饰 private Singleton() { } // 3.提供公有的get方法负责将对象返回出去,使用public static关键字共同修饰 public static Singleton getInstance() { //return sin; if(null == sin) { sin = new Singleton(); } return sin; }}
继承
- 当多个类之间有相同的特征和行为时,可以将相同的内容提取出来组成一个公共类,让多个类吸收公共类中已有特征和行为而在多个类型只需要编写自己独有特征和行为的机制,叫做继承。
- 在Java语言中使用extends(扩展)关键字来表示继承关系。
- 使用继承提高了代码的复用性,可维护性及扩展性,是多态的前提条件。
特点
- 子类不能继承父类的构造方法(构造方法要求和类名相同)和私有方法(只能在本类中使用),但私有成员变量可以被继承只是不能直接访问。
- 无论使用何种方式构造子类的对象时都会自动调用父类的无参构造方法,来初始化从父类中继承的成员变量,相当于在构造方法的第一行增加代码**super()**的效果。
- 使用继承必须满足逻辑关系:子类 is a 父类,也就是不能滥用继承。
- Java语言中只支持单继承不支持多继承,也就是说一个子类只能有一个父类,但一个父类可以有多个子类。
方法重写
- 从父类中继承下来的方法不满足子类的需求时,就需要在子类中重新写一个和父类一样的方法来覆盖从父类中继承下来的版本,该方式就叫做方法的重写(Override)。
重写原则
- 要求方法名相同、参数列表相同以及返回值类型相同,从Java5开始允许返回子类类型。
- 要求方法的访问权限不能变小,可以相同或者变大。
- 要求方法不能抛出更大的异常(异常机制)。
访问控制
- public修饰的成员可以在任意位置使用。
- private修饰的成员只能在本类内部使用。
- 通常情况下,成员方法都使用public关键字修饰,成员变量都使用private 关键字修饰。
package语句
- 定义类时需要指定类的名称,但如果仅仅将类名作为类的唯一标识,会出现命名冲突的问题。
- 在Java语言中,用包(package)的概念来解决命名冲突的问题。
定义包的规范
- org.apache.commons.lang.StringUtil
- 其中StringUtils是类名而org.apache.commons.lang是多层包名,其含义如下:org.apache表示公司或组织的信息(是这个公司(或组织)域名的反写);common 表示项目的名称信息;lang 表示模块的名称信息。
final关键字
- final本意为"最终的、不可改变的",可以修饰类、成员方法以及成员变量。
使用方式
- final关键字修饰类体现在该类不能被继承。
- 主要用于防止滥用继承,如:java.lang.String类等。
- final关键字修饰成员方法体现在该方法不能被重写但可以被继承。
- 主要用于防止不经意间造成重写,如:java.text.Dateformat类中format方法等。
- final关键字修饰成员变量体现在该变量必须初始化且不能改变。
- 主要用于防止不经意间造成改变,如:java.lang.Thread类中MAX_PRIORITY等。
常量
- 在以后的开发中很少单独使用final关键字来修饰成员变量,通常使用 public static final关键字共同修饰成员变量来表达常量的含义,常量的命名规范要求是所有字母都要大写,不同的单词之间采用下划线连接。
多态
-
多态的实际意义在于屏蔽不同子类的差异性实现通用的编程带来不同的效果。
public static void draw(Rect r) { r.show();}public static void draw(Circle c) { c.show();}// 多态的使用场合一:通过参数传递形成了多态public static void draw(Shape s) { // 编译阶段调用父类的版本,运行阶段调用子类重写以后的版本 s.show();}
-
父类类型 引用变量名 = new 子类类型();
-
父类类型的引用指向子类类型的对象
特点
- 当父类类型的引用指向子类类型的对象时,父类类型的引用可以直接调用父类独有的方法;父类类型的引用不可以直接调用子类独有的方法。
- 对于父子类都有的非静态方法来说,编译阶段调用父类版本,运行阶段调用子类重写的版本(动态绑定)。
- 对于父子类都有的静态方法来说,编译和运行阶段都调用父类版本。
类型转换
- 自动类型转换(向上转型):子类转为父类。
- 强制类型转换(向下转型或显式类型转换):父类转为子类。
- 引用数据类型之间的转换必须发生在父子类之间,否则编译报错。
类型转换注意事项
-
若强转的目标类型并不是该引用真正指向的数据类型时则编译通过,运行阶段发生类型转换异常。
-
为了避免上述错误的发生,应该在强转之前进行判断,格式如下:
if(引用变量 instanceof 数据类型)
判断引用变量指向的对象是否为后面的数据类型
// 多态的使用场合之二: 直接在方法体中使用父类/抽象类的引用指向子类类型的对象// 相当于从Rect类型到Shape类型的转换 也就是子类到父类的转换 小到大的转换 自动类型转换Shape sr = new Rect(7, 8, 9, 10);// 相当于从Shape类型到Rect类型的转换 也就是父类到子类的转换 大到小的转换 强制类型转换int ib = ((Rect) sr).getLen();// 希望将Shape类型转换为String类型 强制类型转换要求必须拥有父子类关系String str1 = (String)sr; // Error// 希望将Shape类型强制转换为Circle类型 下面没有报错// 编译ok,但运行阶段发生ClassCastException类型转换异常// sr真正指向Rect类型Circle c1 = (Circle)sr; // 在强制类型转换之前应该使用instanceof进行类型的判断// 判断sr指向堆区内存中的对象是否为Circle类型,若是则返回true,否则返回falseif(sr instanceof Circle) { System.out.println("可以放心地转换了!"); Circle c1 = (Circle)sr;} else { System.out.println("强转有风险,操作需谨慎!");}
抽象类
-
抽象方法:主要指不能具体实现的方法并且使用abstract关键字修饰,也就是没有方法体。
具体格式如下:
访问权限 abstract 返回值类型 方法名(形参列表);
public abstract void cry();
-
抽象类:主要指不能具体实例化的类并且使用abstract关键字修饰,也就是不能创建对象。
抽象类和抽象方法的关系
- 抽象类中可以有成员变量、构造方法、成员方法;
- 抽象类中可以没有抽象方法,也可以有抽象方法;
- 拥有抽象方法的类必须是抽象类,因此真正意义上的抽象类应该是具有抽象方法并且使用abstract关键字修饰的类。
- 若抽象类没有抽象方法,就失去了不能创建对象的原因(抽象方法无方法体,调用抽象方法无意义,为了避免程序员不小心调用抽象方法,所以规定抽象类不能创建对象)
抽象类的实际意义
- 抽象类的实际意义不在于创建对象而在于被继承。
- 当一个类继承抽象类后必须重写抽象方法,否则该类也变成抽象类,也就是抽象类对子类具有强制性和规范性,因此叫做模板设计模式。
开发经验分享
-
在以后的开发中推荐使用多态的格式,此时父类类型引用直接调用的所有方法一定是父类中拥有的方法,若以后更换子类时,只需要将new关键字后面的子类类型修改而其它地方无需改变就可以立即生效,从而提高了代码的可维护性和可扩展型。
// 1.声明本类类型的引用指向本类类型的对象,没有多态SubAbstractTest sat = new SubAbstractTest();sat.show();// 2.声明AbstractTest类型的引用指向子类的对象,形成了多态// 多态的使用场合之二: 直接在方法体中使用抽象类的引用指向子类类型的对象AbstractTest at = new SubAbstractTest();//AbstractTest at = new SubAbstractTest2();// 编译阶段调用父类版本,运行阶段调用子类版本at.show();
-
该方式的缺点就是:父类引用不能直接调用子类独有的方法,若调用则需要强制类型转换。
((SubAbstractTest2) at).test();
笔试考点
-
private 和 abstract 关键字不能共同修饰一个方法
私有方法不能被继承
-
final 和 abstract 关键字不能共同修饰一个方法
final方法不能被重写
-
static 和 abstract 关键字不能共同修饰一个方法
抽象类不能new对象,static可以通过类名调用方法,抽象意义就不存在了
接口
- 所有方法都为抽象方法,关键字是interface。
- 一个类可以实现多个接口(弥补了不能继承多个类的缺憾),关键字是implements。
抽象类和接口的主要区别(笔试题)
-
定义抽象类的关键字是abstract class,而定义接口的关键字是interface。
-
继承抽象类的关键字是extends,而实现接口的关键字是implements。
-
继承抽象类支持单继承,而实现接口支持多实现。
-
抽象类中可以有构造方法,而接口中不可以有构造方法。
-
抽象类中可以有成员变量,而接口中只可以有常量。
-
抽象类中可以有成员方法,而接口中只可以有抽象方法。
-
抽象类中增加方法时子类可以不用重写(抽象类有成员方法),而接口中增加方法时实现类需要重写(接口中只有抽象方法,不重写实现类要变成抽象类)(Java8以前的版本)。
-
从Java8开始增加新特性,接口中允许出现非抽象方法和静态方法,但非抽象方法需要使用default关键字修饰(避免在接口增加新方法后,所有实现类都要重写)。
//接口中// 增加静态方法 隶属于类层级,也就是接口层级public static void test() { System.out.println("这里是静态方法,可以直接通过接口名.的方式调用,省略对象的创建");}//实现该接口的类中//可以使用 接口名称. 的方式调用接口中的静态方法
-
从Java9开始增加新特性,接口中允许出现私有方法(实现代码的复用)。
//接口中// 将两个默认方法中重复的代码可以提取出来打包成一个方法在下面的两个方法中分别调用即可private void show() { // 只在本类中使用,用private关键字 System.out.println("在以后的开发中尽量减少重复的代码,也就是减少代码的冗余!");}// 增加非抽象方法public default void show1() { show(); //System.out.println("在以后的开发中尽量减少重复的代码,也就是减少代码的冗余!"); System.out.println("show1方法中:这里仅仅是接口中的默认功能,实现类可以自由选择是否重写!");}// 增加非抽象方法public default void show2() { show(); //System.out.println("在以后的开发中尽量减少重复的代码,也就是减少代码的冗余!"); System.out.println("show2方法中:这里仅仅是接口中的默认功能,实现类可以自由选择是否重写!");}
内部类
-
当一个类存在的价值仅仅是为某一个类单独服务时,那么就可以将这个类定义为所服务类中的内部类,这样可以隐藏该类的实现细节并且可以方便的访问外部类的私有成员而不再需要提供公有的get和set方法。
-
分类:
- 普通内部类:直接将一个类的定义放在另外一个类的类体中。
- 静态内部类:使用static关键字修饰的内部类,隶属于类层级。
- 局部内部类:直接将一个类的定义放在方法体的内部时。
- 匿名内部类:就是指没有名字的内部类。
-
匿名内部类的语法格式:接口/父类类型 引用变量名 = new 接口/父类类型() { 方法的重写 };
枚举
- 在日常生活中某些事物的取值只有明确的几个固定值(如一年中的所有季节:春、夏、秋、冬),此时描述这些事物的所有值都可以一一列举出来,而这个列举出来的类型就叫做枚举类型。
枚举的定义
-
使用public static final表示的常量描述较为繁琐,使用enum关键字来定义枚举类型取代常量,枚举类型是从Java5开始增加的一种引用数据类型。
-
枚举值就是当前类的类型,也就是指向本类的对象,默认使用public static final关键字共同修饰,因此采用枚举类型.的方式调用。
//DirectionTest.javaDirectionEnum de = DirectionEnum.DOWN;
-
枚举类可以自定义构造方法,但是构造方法的修饰符必须是private,默认也是私有的。
/** * 编程实现所有方向的枚举,所有的方向:向上、向下、向左、向右 枚举类型要求所有枚举值必须放在枚举类型的最前面 */public enum DirectionEnum { // 2.声明本类类型的引用指向本类类型的对象 UP("向上") , DOWN("向下") , LEFT("向左") , RIGHT("向右"); private final String desc; // 用于描述方向字符串的成员变量 // 通过构造方法实现成员变量的初始化,更加灵活 // 1.私有化构造方法,此时该构造方法只能在本类的内部使用 private DirectionEnum(String desc) { this.desc = desc; } // 通过公有的get方法可以在本类的外部访问该类成员变量的数值 public String getDesc() { return desc; }}
枚举类实现接口的方式
-
枚举类实现接口后需要重写抽象方法,重写方法的方式有两种:重写一个,或者每个对象都重写。
/** * 编程实现所有方向的枚举,所有的方向:向上、向下、向左、向右 枚举类型要求所有枚举值必须放在枚举类型的最前面 */public enum DirectionEnum implements DirectionInterface { // 2.声明本类类型的引用指向本类类型的对象 // 匿名内部类的语法格式:接口/父类类型 引用变量名 = new 接口/父类类型() { 方法的重写 }; // public static final Direction UP = new Direction("向上") { 方法的重写 }; UP("向上") { @Override public void show() { System.out.println("贪吃蛇向上移动了一下!"); } }, DOWN("向下") { @Override public void show() { System.out.println("贪吃蛇向下移动了一下!"); } }, LEFT("向左") { @Override public void show() { System.out.println("左移了一下!"); } }, RIGHT("向右") { @Override public void show() { System.out.println("右移了一下!"); } }; private final String desc; // 用于描述方向字符串的成员变量 // 通过构造方法实现成员变量的初始化,更加灵活 // 1.私有化构造方法,此时该构造方法只能在本类的内部使用 private DirectionEnum(String desc) { this.desc = desc; } // 通过公有的get方法可以在本类的外部访问该类成员变量的数值 public String getDesc() { return desc; } // 整个枚举类型只重写一次,所有对象调用同一个 /*@Override public void show() { System.out.println("现在可以实现接口中抽象方法的重写了!"); }*/}
发表评论
最新留言
关于作者
