Java面向对象编程(No.12)
1、面向过程思想与面向对象思想
1.1、面向过程思想(Process Oriented Thinking)
- 1.1.1、步骤清晰简单,第一步做什么,第二步做什么…。
- 1.1.2、面向过程适合处理一些较为简单的问题。
1.2、面向对象思想(Object Oriented Thinking)
- 1.2.1、物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考,最后,才对某个分类下的细节进行面向过程的思索。
- 1.2.2、面向对象适合处理复杂的问题,适合处理需要多人协作的问题。
1.3、注意事项(Matters Needing Attention)
对于描述复杂的事物,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象的思路来分析整个系统,但是,具体到微观操作,任然需要面向过程的思路去处理。
2、面向对象编程(Object-Oriented Programming,OOP)
Java的核心思想就是面向对象编程。
2.1、本质(Essence)
面向对象编程的本质就是:“以类的方式组织代码,以对象的方式组织(封装)数据”。
2.2、三大特性(Three Characteristics)
- 2.2.1、封装(Encapsulation)
- 2.2.2、继承(Inherit)
- 2.2.3、多态(Polymorphic)
2.3、注意事项(Matters Needing Attention)
- 2.3.1、从认识论角度考虑是"先有对象后有类",“对象"是"具体的事物”,“类"是"抽象的事物”,是"对对象的抽象"。
- 2.3.2、从代码运行角度考虑是“先有类后有对象”,“类”是“对象的模板”。
3、回顾方法的定义与调用(Review The Definition And Call Of Method)
其示例,如以下代码所示。
package com.xueshanxuehai.OOP;
//引用传递:对象,本质还是值传递
public class DefinitionAndCallMethod {
public static void main(String[] args) {
System.out.println("调用非静态的值传递方法:");
System.out.println("=================================");
int vt = 0;
System.out.println(vt);//0
DefinitionAndCallMethod definitionAndCallMethod = new DefinitionAndCallMethod();//实例化DefinitionAndCallMethod类对象
definitionAndCallMethod.valueTransmission(vt);//调用非静态的值传递方法"valueTransmission"
System.out.println(vt);//0
System.out.println("=================================");
System.out.println("调用静态的引用传递方法:");
System.out.println("=================================");
Person person = new Person();
System.out.println(person.name);//null
referenceTransmission(person, "学山学海");//调用静态的引用传递方法"referenceTransmission"
System.out.println(person.name);//学山学海
System.out.println("=================================");
}
//非静态的值传递方法"valueTransmission"
public void valueTransmission(int vt) {
vt = 1;
}
//静态的引用传递方法"referenceTransmission"
public static void referenceTransmission(Person person, String name) {
person.name = name;//person是一个对象,是一个具体的事物,所以可以改变其属性
}
}
//定义一个Person类,定义一个属性"name"
class Person {
String name;
}
其运行结果,如下图所示。
4、类与对象的关系(Relationship Of Class And Object)
- 4.1、类是一种抽象的数据类型,它是对某一类事物整体描述/定义,但是并不能代表某一个具体的事物。
- 4.1.1、在生活中,如:动物、植物、手机、电脑等。
- 4.1.2、在Java中,如:Person类、Pet类、Car类、Dog类等,这些类都是用来描述/定义某一类具体的事物应该具备的特点和行为。
- 4.2、对象是抽象概念的具体实例。
- 4.2.1、在生活中,张三就是人的一个具体实例,而张三家里的旺财就是狗的一个具体实例。
- 4.2.2、在Java中,能够体现出特点,展现出功能的是具体的实例,而不是一个抽象的概念。
5、类与对象的创建(Creation Of Class And Object)
-
5.1、类对象(Class Object)。
使用New关键字创建类对象时,除了分配内存空间外,还会给创建好的对象进行默认初始化,以及对类中构造器的调用。
-
5.2、示例(Example)。
ClassAndObjectCreation类,如以下代码所示。
package com.xueshanxuehai.OOP; public class ClassAndObjectCreation { public static void main(String[] args) { //类:抽象的,类实例化后会返回一个类对象(即,类的具体实例"对象") Students students1 = new Students();//实例化Student类对象student1 Students students2 = new Students();//实例化Student类对象student2 System.out.println("Student类对象student1重新赋值前"); System.out.println("==================================================="); System.out.println("学生的姓名:"+ students1.name+",学生的年龄:"+ students1.age); students1.study(); System.out.println("==================================================="); System.out.println("Student类对象student1重新赋值后"); System.out.println("==================================================="); students1.name="学山"; students1.age=11; System.out.println("学生的姓名:"+ students1.name+",学生的年龄:"+ students1.age); students1.study(); System.out.println("==================================================="); System.out.println("Student类对象student2重新赋值前"); System.out.println("==================================================="); System.out.println("学生的姓名:"+ students2.name+",学生的年龄:"+ students2.age); students2.study(); System.out.println("==================================================="); System.out.println("Student类对象student2重新赋值后"); System.out.println("==================================================="); students2.name="学海"; students2.age=22; System.out.println("学生的姓名:"+ students2.name+",学生的年龄:"+ students2.age); students2.study(); System.out.println("==================================================="); } }
Students类,如以下代码所示。
package com.xueshanxuehai.OOP; //学生类 public class Students { //属性:字段 String name;//null int age;//0 //静态方法:和类一起加载的 public static void say() { System.out.println("学生在说话"); } //非静态方法:实例化类对象后才会存在 public void study() { System.out.println("\""+this.age+"\"岁的\""+this.name+"\"学生在努力学习"); } }
其运行结果,如下图所示。
-
5.3、注意事项(Matters Needing Attention)。
学习程序的好处:“可以对世界进行更好的建模”。
6、类的构造器详解(Detailed Explanation Of Class Constructor)
类中的构造器也称为构造方法,是在进行创建对象时必须要调用的。
- 6.1、示例(Example)。
ClassConstructor类,如以下代码所示。
package com.xueshanxuehai.OOP;
public class ClassConstructor {
public static void main(String[] args) {
System.out.println("调用无参构造方法");
System.out.println("===============================");
Peoples peoples1 = new Peoples();//实例化Peoples类对象peoples1,调用无参构造方法
System.out.println("姓名:"+peoples1.name+",年龄:"+peoples1.age);
System.out.println("===============================");
System.out.println("调用有参构造方法");
System.out.println("===============================");
Peoples peoples2 = new Peoples("学山学海",22);//实例化Peoples类对象peoples2,调用有参构造方法
System.out.println("姓名:"+peoples2.name+",年龄:"+peoples2.age);
System.out.println("===============================");
}
}
Peoples类,如以下代码所示。
package com.xueshanxuehai.OOP;
public class Peoples {
//属性:字段
String name;//null
int age;//0
//显示定义无参构造方法
public Peoples() {
}
//显示定义有参构造方法:一旦显示定义了有参构造方法,就必须显示定义无参构造方法
public Peoples(String name, int age) {
this.name = name;
this.age = age;
}
//生成类构造器(构造方法)快捷键"Alt+Insert",接着选择菜单"Constructor"选项,然后选择指定参数属性,
//最后若点击“OK”则生成“有参构造方法”,若点击“Select None”则生成“无参构造方法”,若点击“Cancel”则不创建构造方法。
}
其运行结果,如下图所示。
- 6.2、注意事项(Matters Needing Attention)。
- 6.2.1、类构造器(即,构造方法)必须和类的名字相同。
- 6.2.2、类构造器(即,构造方法)必须没有返回类型,也不能为void。
- 6.2.3、一个类即使什么都不写,它也会默认存在一个方法(即,构造方法)。
- 6.2.4、使用New关键字实例化对象时,本质是在调用类构造器(即,构造方法)。
- 6.2.5、类构造器(即,构造方法)一般用来初始化对象的值。
- 6.2.6、一旦显示定义了有参构造方法,就必须显示定义无参构造方法。
7、创建对象内存分析(Create Object Memory Analysis)
CreateObjectMemoryAnalysis类,如以下代码所示。
package com.xueshanxuehai.OOP;
public class CreateObjectMemoryAnalysis {
public static void main(String[] args) {
Pet dog = new Pet();
dog.name = "大黄";
dog.age = 5;
dog.shout();
System.out.println("宠物名称:" + dog.name + ",宠物年龄:" + dog.age);
System.out.println("===========================================");
Pet cat = new Pet();
cat.name = "小花";
cat.age = 3;
cat.shout();
System.out.println("宠物名称:" + cat.name + ",宠物年龄:" + cat.age);
}
}
Pet类,如以下代码所示。
package com.xueshanxuehai.OOP;
public class Pet {
String name;//null
int age;//0
//无参构造方法
public Pet() {
}
public void shout() {
System.out.println("宠物叫了一下");
}
}
其运行结果,如下图所示。
其创建对象内存分析示意图,如下图所示。
8、封装(Encapsulation)
封装(即,数据或信息的隐藏[Data Or Information Hiding]),就是禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问。
一般情况下,程序设计时都追求“高内聚,低耦合”。”高内聚“就是类的内部数据操作细节自己完成,不允许外部干涉;而“低耦合”就是暴露少量的方法给外部使用。
- 8.1、示例(Example)。
Encapsulation类,如以下代码所示。
package com.xueshanxuehai.OOP;
public class Encapsulation {
public static void main(String[] args) {
Human human = new Human();
human.setName("学山");
human.setAge(11);
human.setSex('男');
System.out.println("人员姓名:" + human.getName() + ",年龄:" + human.getAge() + ",性别:" + human.getSex());
human.setName("学海");
human.setAge(-1);
human.setSex('南');
System.out.println("人员姓名:" + human.getName() + ",年龄:" + human.getAge() + ",性别:" + human.getSex());
}
}
Human类,如以下代码所示。
package com.xueshanxuehai.OOP;
public class Human {
//属性(Attribute):字段(field)、成员变量(Member Variable)
//一般封装时,属性私有
private String name;//姓名
private int age;//年龄
private char sex;//性别
//属性name的get方法
public String getName() {
return name;
}
//属性name的set方法
public void setName(String name) {
this.name = name;
}
//属性age的get方法
public int getAge() {
return age;
}
//属性age的set方法(可自定义一些防误判定)
public void setAge(int age) {
if (age >= 0 && age <= 120) {//合理年龄
this.age = age;
} else {//不合理年龄
this.age = -999;
}
}
//属性sex的get方法
public char getSex() {
return sex;
}
//属性sex的set方法(可自定义一些防误判定)
public void setSex(char sex) {
if (sex == '男' || sex == '女') {
this.sex = sex;
} else {
this.sex = '错';
}
}
//生成类属性的get方法与set方法快捷键"Alt+Insert",接着选择菜单"Getter and Setter"选项,然后选择指定参数属性,
//最后若点击“OK”则生成类属性的“get方法与set方法”,若点击“Cancel”则不生成类属性的“get方法与set方法”。
}
其运行结果,如下图所示。
- 8.2、注意事项(Matters Needing Attention)。
- 8.2.1、提高程序的安全性,保护数据。
- 8.2.2、隐藏代码的实现细节。
- 8.2.3、统一接口标准。
- 8.2.4、增加系统可维护性。
9、继承(Inherit)
继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。
- 9.1、示例(Example)。
Inherit类,如以下代码所示。
package com.xueshanxuehai.OOP;
public class Inherit {
public static void main(String[] args) {
Students students = new Students();
students.setName("学山学海");
students.setAge(22);
students.setSex('男');
System.out.println("(学生)姓名:" + students.getName() + ",年龄:" + students.getAge() + ",性别:" + students.getSex());
students.say();
students.eat();
students.rest();
System.out.println("===========================================");
Teachers teachers = new Teachers();
teachers.setName("狂神");
teachers.setAge(33);
teachers.setSex('男');
System.out.println("(教师)姓名:" + teachers.getName() + ",年龄:" + teachers.getAge() + ",性别:" + teachers.getSex());
teachers.say();
teachers.eat();
teachers.rest();
}
}
Human类,如以下代码所示。
package com.xueshanxuehai.OOP;
//Human(人[类])类:父类(基类)
public class Human {
//属性(Attribute):字段(field)、成员变量(Member Variable)
//一般封装时,属性私有
private String name;//姓名
private int age;//年龄
private char sex;//性别
//say方法
public void say() {
System.out.println("说话");
}
//eat方法
public void eat() {
System.out.println("吃饭");
}
//rest方法
public void rest() {
System.out.println("休息");
}
//属性name的get方法
public String getName() {
return name;
}
//属性name的set方法
public void setName(String name) {
this.name = name;
}
//属性age的get方法
public int getAge() {
return age;
}
//属性age的set方法(可自定义一些防误判定)
public void setAge(int age) {
if (age >= 0 && age <= 120) {//合理年龄
this.age = age;
} else {//不合理年龄
this.age = -999;
}
}
//属性sex的get方法
public char getSex() {
return sex;
}
//属性sex的set方法(可自定义一些防误判定)
public void setSex(char sex) {
if (sex == '男' || sex == '女') {
this.sex = sex;
} else {
this.sex = '错';
}
}
//生成类属性的get方法与set方法快捷键"Alt+Insert",接着选择菜单"Getter and Setter"选项,然后选择指定参数属性,最后若点击“OK”则生成类属性的“get方法与set方法”,若点击“Cancel”则不生成类属性的“get方法与set方法”。
//查看Java层次结构(即,类与类之间继承关系树结构)的快捷键"Ctrl+H"
}
Teachers类,如以下代码所示。
package com.xueshanxuehai.OOP;
//教师类:子类(派生类),继承父类(基类)
public class Teachers extends Human {
}
Students类,如以下代码所示。
package com.xueshanxuehai.OOP;
//学生类:子类(派生类),继承父类(基类)
public class Students extends Human {
}
其运行结果,如下图所示。
- 9.2、注意事项(Matters Needing Attention)。
- 9.2.1、Java所有类都默认直接或间接继承Object类。
- 9.2.2、Java所有类只有单继承,没有多继承。
- 9.2.3、继承是类和类之间的一种关系,除此之外,类和类之间的关系还有依赖、组合、聚合等。
- 9.2.4、继承关系的两个类,一个为子类(派生类),一个为父类(基类),子类继承父类,使用关键字”extends“(扩展)来表示,即,子类是父类的扩展。
- 9.2.5、子类和父类之间,从意义上来讲应该具有”is a“的关系,如”学生类是人类、教师类是人类“等。
10、super详解(Detailed Explanation Of Super)
- 10.1、示例(Example)。
Super类,如以下代码所示。
package com.xueshanxuehai.OOP;
public class Super {
public static void main(String[] args) {
Students students = new Students();
students.printField("Super");
students.printMethod();
}
}
Human类,如以下代码所示。
package com.xueshanxuehai.OOP;
//Human(人[类])类:父类(基类)
public class Human {
public Human() {
System.out.println("HumanClass无参构造方法");
}
public Human(String name) {
// this();//隐藏代码:调用当前类无参构造方法,且此代码必须放到第一行
this.name = name;
System.out.println("HumanClass有参构造方法");
}
//属性(Attribute):字段(field)、成员变量(Member Variable)
//一般封装时,属性私有
// private String name;//姓名
protected String name;//姓名
private int age;//年龄
private char sex;//性别
//print方法
public void print() {
System.out.println("HumanClass");
}
//say方法
public void say() {
System.out.println("说话");
}
//eat方法
public void eat() {
System.out.println("吃饭");
}
//rest方法
public void rest() {
System.out.println("休息");
}
//属性name的get方法
public String getName() {
return name;
}
//属性name的set方法
public void setName(String name) {
this.name = name;
}
//属性age的get方法
public int getAge() {
return age;
}
//属性age的set方法(可自定义一些防误判定)
public void setAge(int age) {
if (age >= 0 && age <= 120) {//合理年龄
this.age = age;
} else {//不合理年龄
this.age = -999;
}
}
//属性sex的get方法
public char getSex() {
return sex;
}
//属性sex的set方法(可自定义一些防误判定)
public void setSex(char sex) {
if (sex == '男' || sex == '女') {
this.sex = sex;
} else {
this.sex = '错';
}
}
//生成类属性的get方法与set方法快捷键"Alt+Insert",接着选择菜单"Getter and Setter"选项,然后选择指定参数属性,最后若点击“OK”则生成类属性的“get方法与set方法”,若点击“Cancel”则不生成类属性的“get方法与set方法”。
//查看Java层次结构(即,类与类之间继承关系树结构)的快捷键"Ctrl+H"
}
Students类,如以下代码所示。
package com.xueshanxuehai.OOP;
//学生类:子类(派生类),继承父类(基类)
public class Students extends Human {
public Students() {
// super();//隐藏代码:调用父类无参构造方法,且此代码必须放到第一行
super("Human");//调用父类有参构造方法,且此代码必须放到第一行
// this("Students");//调用当前类有参构造方法,且此代码必须放到第一行
System.out.println("StudentsClass无参构造方法");
}
public Students(String name) {
this.name = name;
System.out.println("StudentsClass有参构造方法");
}
private String name = "Students";
// private String name;
//print方法
public void print() {
System.out.println("StudentsClass");
}
public void printMethod() {
print();//StudentsClass
this.print();//StudentsClass
super.print();//HumanClass
}
public void printField(String name) {
System.out.println(name);//狂神
System.out.println(this.name);//学山学海
System.out.println(super.name);//null
}
}
其运行结果,如下图所示。
-
10.2、super与this的区别(Matters Needing Attention)。
- 10.2.1、super只能在子类继承父类时才可以在子类中使用,this没有继承也能在当前类中使用。
- 10.2.2、super代表父类对象的引用,this代表当前类对象的引用。
- 10.2.3、super()代表父类的构造方法,this()代表当前类的构造方法。
-
10.3、注意事项(Matters Needing Attention)。
- 10.3.1、子类中使用super调用父类的构造方法时,super()必须写在构造方法第一行。
- 10.3.2、当前类中使用this调用当前类的构造方法时,this()必须写在构造方法第一行。
- 10.3.3、super和this不能同时调用构造方法。
- 10.3.4、super只能出现在子类的方法或构造方法中。
- 10.3.5、父类中私有的属性和方法无法被子类继承。
11、方法重写(Method Override)
由于父类的功能子类不一定需要,或者不一定满足子类的需要,所以,这时就需要子类重写父类的方法。
- 11.1、示例(Example)。
MethodOverride类,如以下代码所示。
package com.xueshanxuehai.OOP;
public class MethodOverride {
public static void main(String[] args) {
Override1 o1=new Override1();
o1.test();//静态方法
o1.test1();//非静态方法
Override2 o2=new Override1();//父类的引用指向子类
o2.test();//方法的调用只与定义的数据类型有关
o2.test1();//非静态方法时,子类重写父类的方法
}
}
Override1类,如以下代码所示。
package com.xueshanxuehai.OOP;
//继承
public class Override1 extends Override2{
//子类静态方法
public static void test(){
System.out.println("Override1->test()");
}
//子类非静态方法(子类重写父类的方法)
@Override //注解:有功能的注释
public void test1() {
// super.test1();
System.out.println("Override1->test1()");
}
//生成子类重写父类的方法快捷键"Alt+Insert",接着选择菜单"Override Methods..."选项,然后选择指定子类需重写的父类方法,最后若点击“OK”则生成“子类重写父类的方法”,若点击“Cancel”则不生成“子类重写父类的方法”。
}
Override2类,如以下代码所示。
package com.xueshanxuehai.OOP;
//重写都是方法的重写,与属性无关
public class Override2 {
//父类静态方法
public static void test(){
System.out.println("Override2->test()");
}
//父类非静态方法
public void test1(){
System.out.println("Override2->test1()");
}
}
其运行结果,如下图所示。
- 11.2、注意事项(Matters Needing Attention)。
- 11.2.1、子类继承父类时,子类重写父类的方法,与属性无关。
- 11.2.2、方法名必须相同,参数列表亦必须相同。
- 11.2.3、修饰符:范围可以扩大,但不能缩小(大小比较:public>protected>default>private)。
- 11.2.4、抛出异常:范围可以缩小,但不能扩大。
- 11.2.5、方法的调用只和定义的数据类型有关。
- 11.2.6、子类不能重写父类的static方法(即,“静态方法”,属于类,不属于类的实例)、final方法(即,“最终方法”,无法被子类重写)、private方法(即,“私有方法“,无法被子类重写),子类可以重写父类的其他方法,且调用重写方法时只执行子类的方法。
12、多态(Polymorphic)
多态就是同一方法可以根据发送对象的不同而采用多种不同的行为方式。
-
12.1、存在条件(Existence Condition)。
- 12.1.1、有继承关系。
- 12.1.2、子类重写父类的方法。
- 12.1.3、父类引用指向子类对象。
-
12.2、示例(Example)。
Polymorphic类,如以下代码所示。
package com.xueshanxuehai.OOP;
//多态
public class Polymorphic {
public static void main(String[] args) {
System.out.println("父类(Pets类)对象的调用方法:");
System.out.println("=========================================");
Pets pets = new Pets();//实例化父类对象
pets.shout();
System.out.println("=========================================");
System.out.println("子类(Dog类)对象的调用方法:");
System.out.println("=========================================");
Dog dog = new Dog();//实例化子类对象
dog.shout();
dog.eat();
System.out.println("=========================================");
System.out.println("父类(Pets类)引用指向子类(Dog类)对象的调用方法:");
System.out.println("=========================================");
Pets pets1 = new Dog();//父类引用指向子类对象
pets1.shout();
((Dog)pets1).eat();
System.out.println("=========================================");
System.out.println("Object类引用指向子类(Dog类)对象的调用方法:");
System.out.println("=========================================");
Object object = new Dog();//Object类引用指向Dog类对象
((Dog)object).shout();
((Dog)object).eat();
System.out.println("=========================================");
}
}
Pets类,如以下代码所示。
package com.xueshanxuehai.OOP;
//父类
public class Pets {
public void shout() {//父类方法
System.out.println("宠物叫了一下");
}
}
Dog类,如以下代码所示。
package com.xueshanxuehai.OOP;
//继承:子类继承父类
public class Dog extends Pets {
@Override
public void shout() {//子类重写父类方法
// super.shout();
System.out.println("狗叫了一声");
}
public void eat(){
System.out.println("狗吃食物");
}
}
其运行结果,如下图所示。
- 12.2、注意事项(Matters Needing Attention)。
- 12.2.1、动态编译:只有在执行时才能确定类型的最终状态,从而增强可扩展性。
- 12.2.2、一个对象的实际类型是确定的,但可以指向的引用类型是不确定的(如,父类的引用指向子类对象或者Object类的引用指向任意类对象)。
- 12.2.3、子类调用的方法可以是自己的或者是父类的,父类可以指向子类,但不能调用子类独有的方法。
- 12.2.4、对象能调用哪些方法,主要和对象定义的数据类型有关。
- 12.2.5、多态是方法的多态,属性没有多态性。
- 12.2.6、父类与子类一定要有联系,否则会类型转换异常(ClassCastException)。
13、instanceof和类型转换(Instanceof And Type Conversion)
-
13.1、instanceof
主要用作判断一个对象是什么引用类型。
-
13.2、示例(Example)。
InstanceofAndTypeConversion类,如以下代码所示。
package com.xueshanxuehai.OOP;
public class InstanceofAndTypeConversion {
public static void main(String[] args) {
//Object->Peoples->Scientists
//Object->Peoples->Polices
//Object->String
System.out.println("instanceof的使用方法");
System.out.println("===============================");
Object object = new Scientists();
System.out.println(object instanceof Object);//true
System.out.println(object instanceof Peoples);//true
System.out.println(object instanceof Scientists);//true
System.out.println(object instanceof Polices);//false
System.out.println(object instanceof String);//false
System.out.println("=================");
Peoples peoples = new Scientists();
System.out.println(peoples instanceof Object);//true
System.out.println(peoples instanceof Peoples);//true
System.out.println(peoples instanceof Scientists);//true
System.out.println(peoples instanceof Polices);//false
// System.out.println(peoples instanceof String);//编译报错
System.out.println("=================");
Scientists scientists = new Scientists();
System.out.println(scientists instanceof Object);//true
System.out.println(scientists instanceof Peoples);//true
System.out.println(scientists instanceof Scientists);//true
// System.out.println(scientists instanceof Polices);//编译报错
// System.out.println(scientists instanceof String);//编译报错
System.out.println("===============================");
System.out.println("引用类型转换的使用方法");
System.out.println("===============================");
Peoples peoples1 = new Scientists();//父类引用指向子类对象,无需强制转换(低类型->高类型)
((Scientists) peoples).study();//需强制转换(高类型->低类型)
System.out.println("===============================");
}
}
Peoples类,如以下代码所示。
package com.xueshanxuehai.OOP;
public class Peoples {
}
Scientists类,如以下代码所示。
package com.xueshanxuehai.OOP;
public class Scientists extends Peoples{
public void study(){
System.out.println("学习");
}
}
Polices类,如以下代码所示。
package com.xueshanxuehai.OOP;
public class Polices extends Peoples{
}
其运行结果,如下图所示。
- 13.3、注意事项(Matters Needing Attention)。
- 13.3.1、父类引用指向子类对象。
- 13.3.2、把子类转换为父类,向上转型(由低类型到高类型),不需要强制类型转换。
- 13.3.3、把父类转换为子类,向下转型(由高类型到低类型),需要强制类型转换。
- 13.3.4、类型转换会方便方法的调用,减少重复的代码,从而使代码更简洁。
14、static关键字详解(Detailed Explanation Of Static Keyword)
- 14.1、示例(Example)。
类,如以下代码所示。
package com.xueshanxuehai.OOP;
import static java.lang.Math.random;//导入静态包
import static java.lang.Math.PI;//导入静态包
public class Static {
{
System.out.println("匿名代码快");//赋初值,每次类加载时调用
}
static {
System.out.println("静态代码快");//只在类第一次加载时调用
}
public Static() {
System.out.println("类构造方法");//每次类加载时调用
}
public static void main(String[] args) {
Static st1 = new Static();
System.out.println("==========================");
Static st2 = new Static();
System.out.println("==========================");
System.out.println("调用随机数方法:" + random());//调用随机数方法
System.out.println("调用PI常量:" + PI);//调用PI常量
System.out.println("==========================");
}
}
其运行结果,如下图所示。
- 14.2、注意事项(Matters Needing Attention)。
- 14.2.1、类加载时执行顺序:“静态代码快->匿名代码快->类构造方法”,且“静态代码快”只在类第一次加载时执行调用。
- 14.2.2、可以导入静态包更方便的调用方法。
15、抽象类(Abstract Class)
abstract修饰符可以修饰类或方法,若修饰类,那该类就是抽象类;若修饰方法,那该方法就是抽象方法。
- 15.1、示例(Example)。
Abstract类,如以下代码所示。
package com.xueshanxuehai.OOP;
//抽象类(单继承)
public abstract class Abstract {
public abstract void abstractMethod();//抽象方法(只有方法声明,没有方法实现)
public Abstract() {//抽象类构造方法
System.out.println("抽象类Abstract构造方法");
}
public static void main(String[] args) {
//new Abstract();//抽象类不能使用new关键字来创建对象,它是用来让子类继承的
//new Abstract2();//抽象类不能使用new关键字来创建对象,它是用来让子类继承的
new Abstract1().abstractMethod();
}
}
Abstract1类,如以下代码所示。
package com.xueshanxuehai.OOP;
//子类继承抽象类,且子类不是抽象类时,那么必须要实现抽象类没有实现的抽象方法
public class Abstract1 extends Abstract {
@Override
public void abstractMethod() {
System.out.println("Abstract1->abstractMethod()");
}
}
Abstract2类,如以下代码所示。
package com.xueshanxuehai.OOP;
//子类继承抽象类,且子类是抽象类时,那么不需要实现抽象类没有实现的抽象方法
public abstract class Abstract2 extends Abstract {
}
其运行结果,如下图所示。
- 15.2、注意事项(Matters Needing Attention)。
- 15.2.1、抽象类可以没有抽象方法,但有抽象方法的类一定要声明抽象类。
- 15.2.2、抽象类不能使用new关键字来创建对象,它是用来让子类继承的。
- 15.2.3、抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的。
- 15.2.4、子类继承抽象类,那么必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类。
16、接口的定义与实现(Definition And Implementation Of Interface)
接口就是规范,定义的是一组规则,体现了现实世界中“如果你是…则必须能…”的思想。比如:“如果你是汽车,则必须能跑起来”等。
接口的本质是契约,就像我们人间的法律一样,制定好后大家都遵守。
OO(面向对象)的精髓就是对对象的抽象,最能体现这一点的就是接口。为什么我们讨论设计模式(23种)都只针对具备了抽象能力的语言(如:C++、Java、C#等),就是因为设计模式所研究的实际上就是如何合理的去抽象。
- 16.1、示例(Example)。
Interface类,如以下代码所示。
package com.xueshanxuehai.OOP;
public class Interface {
public static void main(String[] args) {
System.out.println("接口的定义与实现");
System.out.println("===============================");
UserServiceImpl userService = new UserServiceImpl();
System.out.println("调用接口(UserService)的属性(age):" + UserService.age);
System.out.println("调用接口(UserService)的方法(add):");
userService.add("新增");
System.out.println("调用接口(UserService)的方法(delete):");
userService.delete("删除");
System.out.println("调用接口(UserService)的方法(update):");
userService.update("更改");
System.out.println("调用接口(UserService)的方法(query):");
userService.query("查询");
System.out.println("===============================");
}
}
UserService接口,如以下代码所示。
package com.xueshanxuehai.OOP;
//接口:都需要有实现类
public interface UserService {
//接口中定义的所有变量默认都是静态常量(使用默认修饰符public static final)
//public static final int age=99;//等价于int age=99
int age = 99;
//接口中定义的所有方法默认都是抽象的(使用默认修饰符public abstract)
//public abstract void add(String name);//等价于void add(String name)
//public abstract void delete(String name);//等价于void delete(String name)
//public abstract void update(String name);//等价于void update(String name)
//public abstract void query(String name);//等价于void query(String name)
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
}
TimerService接口,如以下代码所示。
package com.xueshanxuehai.OOP;
//接口:都需要有实现类
public interface TimerService {
//接口中定义的所有方法默认都是抽象的(使用默认修饰符public abstract)
void timer(int interval);
}
UserServiceImpl类,如以下代码所示。
package com.xueshanxuehai.OOP;
//实现接口类:必须要重写接口中的方法,可以实现多个接口,即,可以实现多继承
public class UserServiceImpl implements UserService, TimerService {
@Override
public void add(String name) {
System.out.println("UserServiceImpl->add()");
}
@Override
public void delete(String name) {
System.out.println("UserServiceImpl->delete()");
}
@Override
public void update(String name) {
System.out.println("UserServiceImpl->update()");
}
@Override
public void query(String name) {
System.out.println("UserServiceImpl->query()");
}
@Override
public void timer(int interval) {
System.out.println("UserServiceImpl->timer()");
}
}
其运行结果,如下图所示。
- 16.2、注意事项(Matters Needing Attention)。
- 16.2.1、接口都要有实现类,一个实现类可实现多个接口,即,接口可以实现多继承(而类只能单继承)。
- 16.2.2、接口实现类必须要重写接口中的方法。
- 16.2.3、接口没有构造方法,接口不能被实例化。
- 16.2.4、接口中定义的所有变量默认都是静态常量(使用默认修饰符public static final),且可以不用写其默认修饰符。
- 16.2.5、接口中定义的所有方法默认都是抽象的(使用默认修饰符public abstract),且可以不用写其默认修饰符。
- 16.2.6、普通类:只有具体实现;抽象类:有具体实现和规范(抽象方法);接口:只有规范(抽象方法)。
- 16.2.7、声明类的关键字是“class”,声明接口的关键字是“interface”。
17、内部类(Inner Class)
内部类就是在一个类的内部再定义一个类。比如:A类中定义一个B类,那么B类相对于A类来说就是内部类,而A类相对于B类来说就是外部类。
-
17.1、类别(Classification)。
- 17.1.1、成员内部类(Member Inner Class)。
- 17.1.2、静态内部类(Static Inner Class)。
- 17.1.3、局部内部类(Local Inner Class)。
- 17.1.4、匿名内部类(Anonymous Inner Class)。
-
17.2、示例(Example)。
InnerClass类,如以下代码所示。
package com.xueshanxuehai.OOP;
public class InnerClass {
public static void main(String[] args) {
Outer outer = new Outer();//实例化外部类
System.out.println("成员内部类");
System.out.println("==============================");
Outer.MemberInner inner = outer.new MemberInner();//通过外部类来实例化内部类
inner.memberIn();//调用成员内部类公有方法
inner.getID();//调用成员内部类对应的外部类私有属性
inner.getOut();//调用成员内部类对应的外部类私有方法
System.out.println("==============================");
System.out.println("静态内部类");
System.out.println("==============================");
Outer.StaticInner.staticIn();//调用静态内部类静态方法
System.out.println("==============================");
System.out.println("局部内部类");
System.out.println("==============================");
outer.outerOut();//调用外部类公有方法的局部内部类公有方法
System.out.println("==============================");
System.out.println("匿名内部类");
System.out.println("==============================");
//匿名内部类中,没有名字初始化类,也不用将实例保存到对象变量
new OtherClass().other();
InnerClassInterface ici = new InnerClassInterface() {
@Override
public void ici() {
System.out.println("重写接口抽象方法");
}
};
ici.ici();//调用接口抽象方法
System.out.println("==============================");
}
}
Outer类,如以下代码所示。
package com.xueshanxuehai.OOP;
public class Outer {
private int id = 11;
private void out() {
System.out.println("这是外部类的私有方法");
}
public class MemberInner {//成员内部类
public void memberIn() {
System.out.println("这是成员内部类的公有方法");
}
public void getID() {
System.out.println("这是外部类的私有属性(id):" + id);//调用外部类的私有属性
}
public void getOut() {
out();//调用外部类私有方法
}
}
public static class StaticInner {//静态内部类
public static void staticIn() {
System.out.println("这是静态内部类的静态方法");
}
}
public void outerOut() {
class LocalInner {//局部内部类
public void localIn() {
System.out.println("这是局部内部类的公有方法");
}
}
LocalInner localInner = new LocalInner();//实例化局部内部类
localInner.localIn();//调用局部内部类公有方法
}
}
//一个Java类中可以有很多个class类,但只允许有一个public class类
class OtherClass {
public void other() {
System.out.println("OtherClass");
}
public static void main(String[] args) {
}
}
//接口
interface InnerClassInterface {
//public abstract void ici();//等价于void ici()
void ici();//接口抽象方法
}
其运行结果,如下图所示。
- 17.3、注意事项(Matters Needing Attention)。
- 17.3.1、通过外部类来实例化内部类。
- 17.3.2、成员内部类可以调用外部类的私有属性与私有方法。
- 17.3.3、一个Java类中可以有很多个class类,但只允许有一个public class类。
- 17.3.4、匿名内部类中,没有名字初始化类,也不用将实例保存到对象变量。