七. 面向对象

七. 面向对象

7.1 面向对象概述

7.2 面向对象相关概念

  • 类型

  • 对象

  • 对象的构成(分析)

  • /**
    * 面向对象相关的概念:
    * 类型:class
    * 对对象的抽象的描述。是某一类事物的总体的称呼。
    * 例子:动物、狗、猫、人、树、车、学生、老师。
    *
    * 对象:object
    * 某种类型的具体的实例。
    * 例子:动物园的那只老虎、我家的那只泰迪、邻居家的那只小猫、季程。教学楼门前的那颗大柳树。杨老师的那辆捷安特。季程。杨老师。
    *  
    * 对象的构成:
    * 属性+功能。
    * 属性:静态的,代表了对象拥有的内容。
    * 功能:动态的,代表了对象会做什么。
    *  
    * 现实世界中是先有类型还是先有对象:
    * 先有对象,根据某些对象具有相似的功能和属性,抽象了一个类型的概念。
    *
    *S

7.3 面向过程和面向对象对比

 /*  面向对象:java 是纯粹的面向对象的编程语言。
* 面向过程:c 语言是纯粹的面向过程的编程语言。
*  
* 面向过程:一种思维模式。
* 就是将要解决的问题分解为若干个步骤,按照一定的顺序,执行这些步骤代码即可。是一种线性的思维。
* 问题:
* 1:面向过程的思维适合中小型问题,功能模块相对比较少,使用线性的思维组织执行这些模块,相对容易。
* 不适用比较大的项目,模块很负责,也很多,很难使用线性的思维去组织起来。
* 2:面向过程代码的复用性很差。
*  
* 使用面向过程的思维开车去拉萨:
* 先保定-石家庄-太原--银川--兰州--西宁--拉萨
* 面向对象:一种思维模式。
* 将问题中包含的对象分析出来。让对象具有我们需要的功能,然后然对象去执行功能即可完成需求。
* 使用面向对象的思维开车去拉萨:
* 一个司机会开车+一辆车会跑。到拉萨了。

7.4 案例

package com.qf.oop1;

/**
* 使用面向过程的思想来描述:
* 宋丹丹的思想就是典型的面向过程的思想。
*/
public class TestElephant {

public static void main(String[] args) {
openDoor();
elephantIn();
closeDoor();
}

public static void openDoor(){
System.out.println("打开冰箱门");
}

public static void elephantIn(){
System.out.println("大象装进了冰箱");
}

public static void closeDoor(){
System.out.println("关闭冰箱门");
}
}

 

package com.qf.oop1;

/**
* 使用面向对象的思想实现大象装冰箱:
* 1:分析有几个对象:(名词分析法)
* 2个对象:大象 和 冰箱
*
* 2:分析对象应该有什么功能和属性。
* 冰箱:开门,关门
* 大象:钻冰箱
*  
* 3:如何得到你需要的冰箱和大象这两个对象?
* 先定义冰箱和大象的模板。
* 类就是模板。模板中定义了对象的功能和属性。
*  
* 4:使用类 创建你需要的对象。
*  
* 5: 使用对象执行功能。
* 对象变量.方法();
*
*/
public class TestElephantOop {

public static void main(String[] args) {
//创建一个大象
Elephant aiLi = new Elephant();

//创建一个冰箱
Fridge haiEr = new Fridge();

//使用对象执行功能
haiEr.open();
aiLi.enterFridge();
haiEr.close();
}
}
//定义冰箱的模板。
class Fridge{

//定义冰箱具有 功能。
void open(){
System.out.println("冰箱把门打开了");
}

void close(){
System.out.println("冰箱把门关闭了");
}

}
//大象的模板
class Elephant{

void enterFridge(){
System.out.println("大象很聪明,知道钻到冰箱中纳凉~~~");
}

}

 

7.5 类的定义和使用类创建对象

package com.qf.oop1;

/**
* 使用面向对象的思想实现大象装冰箱:
* 1:分析有几个对象:(名词分析法)
* 2个对象:大象 和 冰箱
*
* 2:分析对象应该有什么功能和属性。
* 冰箱:开门,关门
* 大象:钻冰箱
*  
* 3:如何得到你需要的冰箱和大象这两个对象?
* 先定义冰箱和大象的模板。
* 类就是模板。模板中定义了对象的功能和属性。
*  
* 4:使用类 创建你需要的对象。
*  
* 5: 使用对象执行功能。
* 对象变量.方法();
*  
* 定义类的语法:
* [类的修饰符 public] class 类名{
* //类体
* }
*  
* class:是java的关键字,是用来定义类模板的。
* 类名:是一种标识符,命名规范:首字符大写,遵循驼峰命名法。类名要能体现类描述的对象的内容。
* {类体}
* 描述对象有什么功能和什么属性:
* 功能:成员方法,只写必要组成部分。
* 属性:成员变量。
*  
* 模板的名字:看成一种类型
*
*/
public class TestElephantOop {

public static void main(String[] args) {

//创建一个大象
Elephant aiLi = new Elephant();
//访问对象的属性。
aiLi.size = 100;

//创建一个冰箱
Fridge haiEr = new Fridge();
haiEr.capacity = 150;

//使用对象执行功能
haiEr.open();
boolean result = aiLi.enterFridge(haiEr);
if(result){
System.out.println("大象身材纤细,成功钻进了冰箱!");
}else{
System.out.println("大象身材臃肿,该减肥了。");
}
haiEr.close();
}
}


//定义冰箱的模板。
class Fridge{
//容积的属性
int capacity;

//定义冰箱具有 功能。
void open(){
System.out.println("冰箱把门打开了");
}

void close(){
System.out.println("冰箱把门关闭了");
}
}

//大象的模板
class Elephant{
//大象的体积
int size;

boolean enterFridge(Fridge fridge){
if(size <= fridge.capacity){
return true;
}
return false;
}
}
  • package com.qf.oop1;

    /**
    * 使用面向对象的思想模拟:农夫与蛇的寓言故事。
    *
    * 1:分析有几个对象
    * 2个:农夫 蛇
    * 2:分析对象的功能:
    * 农夫:救助蛇、死亡。
    * 蛇:苏醒、咬人。
    * 3:定义类来描述两个对象。
    *
    * 4: 使用类创建对象。
    *
    * 5: 使用对象调用方法。
    *

    * 类中包含的内容:
    * 1:属性
    * 变量:成员变量|成员字段|成员属性|实例变量|实例属性|对象属性
    * 变量的类型:java支持的任意类型。
    *
    * 2:功能
    * 方法:成员方法|实例方法
    *
    */
    public class TestFarmerAndSnake {

    public static void main(String[] args) {
    Farmer xu = new Farmer();
    xu.name = "许仙";

    Snake bai = new Snake();
    bai.name = "白娘子";

    xu.save(bai);
    bai.attack(xu);
    }
    }

    class Farmer{
    String name;

    void save(Snake snake){
    System.out.println(name + "\t生性善良,将\t" + snake.name + "\t轻轻揣到了怀里!");
    snake.awake();
    }

    void die(){
    System.out.println(name + "\t 挂了!!");
    }
    }

    class Snake{
    String name;

    void awake(){
    System.out.println(name + "\t感觉到一股暖流传遍全身,慢慢苏醒过来!");
    }

    void attack(Farmer farmer){
    System.out.println(name + "\t 狠狠的咬了 " + farmer.name + " 一口!");
    farmer.die();
    }
    }

7.6 构造方法

  • new Farmer(); Farmer 类的构造方法|构造器。

  • 构造方法特点

  • 构造方法重载

  • /**
    * 构造方法的特点:
    * 1:构造方法必须与所在的类同名。
    * 2:构造方法没有返回值。也不是void。返回值部分什么都不能写。
    * 3:任何的一个类,至少要有一个构造方法。如果在类中 没有显式的定义一个构造方法,那么编译器会帮助生成一个:默认无参空实现的构造方法。
    * 4:如果在类中显式的定义了任何一个构造方法,那么编译器就不再提供默认无参空实现的构造方法了。
    * 5:构造方法也能够重载。
    * 6:使用 new 关键字来调用。
    * 7:构造方法作用:对对象进行属性的初始化。
    */
    package com.qf.oop1;

    public class TestStudent {

    public static void main(String[] args) {
    Student san = new Student("张三",21,"男",60);
    san.study();
    san.playGame();

    san.show();


    Student si = new Student("李四",22,"男",70);
    si.study();
    si.playGame();

    si.show();
    }
    }

    // 定义一个学生的模板。来描述学生对象。属性:姓名、年龄、性别、分数。 功能:学习(会影响分数),玩游戏(会影响分数)。
    // 定义一个默认无参的空实现构造方法,定义一个带参数的,通过参数给四个属性赋值。创建2个学生对象,你自己和你同学。
    class Student {

    String name;
    int age;
    String gender;
    int score;

    public Student() {
    }

    public Student(String _name, int _age, String _gender, int _score) {
    name = _name;
    age = _age;
    ,,
    System.out.println(name + "\t不努力学习、上课玩游戏、成绩从[" + score + "]降低到了:" + --score);
    }

    void show(){
    System.out.println("姓名 : " + name + " 年龄 : " + age + " 性别 : " + gender + " 分数 : " +score);
    }

    }

7.7 创建对象过程

package com.qf.oop1;

/**
* 对象的创建的过程说明:
* 1:将需要创建的对象的类文件class文件加载到jvm管理的内存中(方法区)。(类加载 只执行一次)。
* 2:new 关键向 jvm 申请一块堆内存。jvm 会根据类型中定义的实例变量在堆内存中分配相应的空间。
* 给每一个实例变量都分配内存。jvm并给每个成员变量执行默认初始化。
* 默认初始化的规则:整数:0 浮点数:0.0 布尔:false,char:'\u0000'.引用数据类型:null。
* 对象已经创建完毕了,只是对象的属性的值不是我们需要的。
* 3:执行成员变量声明处的赋值。
* 4:执行构造方法中代码。对象初始化完毕。
* 5:由new关键字将该对象的内存地址返回赋值给左边的变量。
*/
public class TestStudent {

public static void main(String[] args) {
Student student = new Student();
student.show();

Student san = new Student("张三",21,"男",60);
san.study();
san.playGame();

san.show();


Student si = new Student("李四",22,"男",70);
si.study();
si.playGame();

si.show();

}
}

// 定义一个学生的模板。来描述学生对象。属性:姓名、年龄、性别、分数。 功能:学习(会影响分数),玩游戏(会影响分数)。
// 定义一个默认无参的空实现构造方法,定义一个带参数的,通过参数给四个属性赋值。创建2个学生对象,你自己和你同学。
class Student {
String name;
int age;
String gender;
int score = 60;

public Student() {
score = 70;
}

public Student(String _name, int _age, String _gender, int _score) {
name = _name;
age = _age;
gender = _gender;
score = _score;
}

void study() {
System.out.println(name + "\t努力学习、成绩从[" + score + "]提高到了:" + (score+= 5));
}

void playGame() {
System.out.println(name + "\t不努力学习、上课玩游戏、成绩从[" + score + "]降低到了:" + --score);
}

void show(){
System.out.println("姓名 : " + name + " 年龄 : " + age + " 性别 : " + gender + " 分数 : " +score);
}
}

7.8 对象内存图

7.9 局部变量和成员变量

/**
* 成员变量和局部变量的区别:
* 1:作用域不同,
* 成员变量的作用域是整个类中的所有的方法。
* 局部变量的作用域是定义的所在的方法内部。
* 2:定义的位置不同
* 一个是在类体中。
* 一个是在方法中。
* 3:内存分配位置不同
* 局部在 栈中。
* 成员在堆中。
* 4:生命周期不同
* 局部变量的生命周期依赖于方法的调用开始和结束。
* 成员变量的生命周期依赖于所在的对象。
* 5:初始化方式不同
* 局部变量必须先赋值后使用。
* 成员变量可以只声明,jvm会执行默认初始化。
* 6:优先级不同。
* 同名的变量,局部变量的优先级高于成员的。
*/

7.10 对象数组及其内存图

package com.qf.oop1;

public class TestStudent {

public static void main(String[] args) {
test();
}

private static void test() {
String[] names = {"义鹏龙","马紫航","季程","王翔","王斯盈","张恒","刘伟龙","孙乐春","宋鹏超",
"杨添龙","刘李强","殷江涛","景蕊鑫","刘冰","王宸","李冠","李城锟","胡开畅","杨健",
"任江华","许凯","杨春星","李云","高宇","张帅","张颖涛","赵鸿威","章鑫","林洋","张舜斌",
"朱映正","王洪勇","姚雪丽","陈芊池","侯佳伟","孙浩","樊旺","刘德信","张晨光",
"张致豪","王佳欣","杰伟航","刘寅玉","刘付达","杨立航","赵梓茗",
"何东虎","杨东升","张战雄","王明磊"};
//使用一个学生数组管理班级的所有的学生。
Student[] students = new Student[names.length];
// for (Student student : students) {
// System.out.println(student);
// }
//对每个元素进行初始化。
for (int i = 0; i < students.length; i++) {
int age = random(19,30);
String gender = Math.random() > 0.5 ? "男":"女";
students[i] = new Student(names[i], age, gender);
students[i].show();
}
System.out.println();
sort(students);

for (int i = 0; i < students.length; i++) {
students[i].show();
}
}

//使用冒泡排序对学生数组排序
public static void sort(Student[] students){
for(int i=0;i<students.length-1;i++){
int minIndex = i;
for(int j=i+1;j<students.length;j++){
if(students[j].age < students[minIndex].age){
minIndex = j;
}
}

if(i != minIndex){
Student temp = students[i];
students[i] = students[minIndex];
students[minIndex] = temp;
}
}
}

private static int random(int min, int max) {
return (int)(Math.random()*(max-min)+min);
}

}

class Student{
String name;
int age = 10;
String gender;


public Student() {
int age  =10;

}

public Student(String _name,int _age,String _gender) {
name = _name;
age = _age;
gender = _gender;
}

void show(){
System.out.println("name = " + name + "\tage = " +age + "\tgender = "+gender);
}
}

 

7.11 类之间的关系介绍

  • 组合

    • 一个类包含了另外一个类的对象,对象做为类的一个成员。表达的是一种包含拥有的关系。

  • 依赖

    • 一个类的对象在另外一个类的一个方法中使用。作为局部变量使用。

      • 作为形参。

      • 直接在方法内创建对象。

  • 继承

  • 实现

7.11 this

package com.qf.oop1;

/**
* this: 代表了当前对象。
* 1:this 是java 的一个关键字。
* 2:this 代表了一个对象的引用。保存了一个对象的地址。
* 3:this 只能在构造方法中,和 实例方法中使用。
* 4:this 在构造方法中使用,this 代表了 刚刚被创建好的对象,正在被初始化的对象。
* 通过this 访问的是类的实例成员。
* 5:this 在实例方法中使用,this代表了调用当前方法的对象。
* 通过this,可以实现不同的对象访问同一个实例方法,访问的是自己对象内部的属性。
* 6:this 可以在构造方法中 访问本类的其他的构造方法。必须在构造方法的第一句调用。
* 等super 结束后理解。
*  
* 总结:
* 1:在构造方法中用于区分成员变量和局部变量。
* 2:以在构造方法中 访问本类的其他的构造方法。
* 3:可以实现不同的对象访问同一个实例方法,访问的是自己对象内部的属性。
* 4:构造方法中,实例方法中,访问本类的成员的时候,前面会默认包含this。
* 5:在构造方法中,和实例方法中,当方法被调用的时候,方法中会包含了一个this,this会被赋值。
* 在构造方法中,将刚刚创建好的对象赋值给this。
* 在实例方法中,将当前正在调用方法的对象的引用赋值给this。
*
*/
public class TestThis {

public static void main(String[] args) {
Person person1 = new Person("Tom1", 12, "boy");
person1.show();

Person person2 = new Person("Tom2", 12, "boy");
person2.show();
}

}

class Person{
String name;
int age = 10;
String gender;


public Person() {
// 访问本类的其他的构造方法
this("张三",10,"男");
this.show();
}


public Person(String name, int age, String gender) {
//区分局部和成员变量
this.name = name;
this.age = age;
this.gender = gender;
}


void show(){
// 访问当前对象的属性
System.out.println("name = " + this.name + "\tage = " +this.age + "\tgender = "+this.gender);
}
}

7.12 程序debug

7.13 面向对象三大特性概述

  • 封装、继承、多态

7.14 封装

  • 封装概念

  • 类成员的访问权限

  • /**
    * 封装:
    * 1:定义模板类的时候需要考虑封装的问题。
    * 2:概念:
    * 在设计类的时候,希望被其他对象访问的部分,对外提供友好的接口,不希望被其他对象访问的部分,实现隐藏。这个过程称为封装。
    * 3:学习封装,学习如何实现控制类成员的隐藏和暴露。
    * 4:通过四个类成员访问权限修饰符发来实现类成员的访问权限的控制。
    *
    * 5:四个类成员的访问权限修饰符。
    * 1:private 私有权限。只能在本类访问。最小的访问权限限制。
    * 2:默认权限 也称为 包私有权限。package权限。
    * 可以本类访问、本包的其他类可以访问。其他的包中的其他的类不能访问。
    * 3:protected 受保护的权限。
    * 可以本类访问、本包的其他类可以访问、其他的包的子类也可以访问。
    * 4:public 公有的意思。
    * 可以本类访问、本包的其他类可以访问、其他的包的类也可以访问。
    * 整个工程的其他的类都可以访问。
    * 类成员的访问权限越小,越安全。
    */
  • 类的访问权限

  • java 源文件 public

  • /*  6:【类访问权限】修饰符
    * 1:public 修饰类,那么该类,可以在整个个工程中使用。
    * 2:默认的 那么该类只能在当前包下其他的类中访问。
    *  
    * 3:一个 .java 源文件中可以定义多个 class ,但是一个原文件中,最多只能有一个使用public 修饰的类。可以没有使用public 修饰的类。
    * 如果一个源文件中包含了一个public 修饰的类,那么该源文件的名字必须与public 修饰的类同名。
    *
    * 4:如果在一个类中访问了其他的包的类,要求使用 import 关键字,将其他包的类导入才可以使用。
    * 5:java.lang.* 该包是默认导入的,核心包。
    * 6:如果一个包中存在多个重名的类,那么必须使用 包名+类名的形式 指定冲突的类来自于哪个包。不能使用 import 形式了。
    * com.qf.encapsulation.Student student = new com.qf.encapsulation.Student();
    * 在java中使用 包名+类名 来唯一的确定一个类。
    */
  • 如何设计类

    • 普通类

      • /* 7:开发中使用什么样的规则去设计类:
        *   	1:所有的属性全部私有化。
        *   		如果某些属性需要被其他的类访问,那么对外提供 getter 和  setter。
        *   	2:类成员的权限越小越好,能私有就私有,然后包私有,然后再public。*/
    • 工具类

  • 封装的优缺点

    • 优点:可以更好的控制类成员的被访问的范围,数据更加的安全了。

    • 缺点:执行效率受到一定程度的影响(影响比较小)

7.15 继承

  • 继承概念

  • 继承的语法

  • java 单继承

  • java.lang.Object

  • package com.qf.inheritance;
    /**
    * 继承相关的概念:
    * 1:子类:继承了其他的类的类。还可以称为:衍生类|派生类。
    * 2:父类:被继承的类。还可以称为:超类|基类。
    * 3:继承:
    * 可以在子类中直接访问父类的成员的过程。
    *
    * 4:继承的语法:
    *   class 子类名   extends 父类名{ //子类体 }
    * extends: 是java的关键字,用来实现子类继承父类的。
    *
    * 5:思考:
    * 子类大?
    * 父类大?
    * 结论:父类表述的对象的范围大,父类类型是包含子类类型的。子类类型更加的具体。
    * 子类强?
    * 父类强?
    * 结论:子类强:子类除了继承了父类的功能之外,还拥有自己特有的功能。
    * 使用:
    * 一般会使用子类对象,父类只是为了被子类继承复用。
    *
    * 6:一个父类可以有多个子类,一个子类只能有一个直接的父类(java 单继承)。
    *
    * 7:java 语言中规定,java只支持单继承,一个子类只能有一个直接的父类,可以有多个间接的父类。
    * 在c++ 语言中,可以支持多继承。一个子类可以有多个直接的父类型。
    * 多继承的好处:快速生成创建一个功能强大的子类。
    * 缺点:如果多个父类中存在同名的方法,会存在使用上冲突。
    * java 不支持多继承,但支持多重继承,可以间接的实现多继承。还比避免了同名的语义上冲突的问题。
    *
    * 8:先有子类还是先有父类?
    * 先有子类后有父类,父类是通过所有的子类的公共的部分提取出来的。
    *
    * 9:java.lang.Object
    * 1: Object 类是jdk 提供的一个类。
    * 2:任何的类都直接的或者间接的继承了 Object类。除了它自身。该类没有继承任何类。
    * 3:如果一个类没有显式直接的继承任何的类。那么默认继承 Object类。
    * 4:如果一个类显式的继承了其他的类,那么就间接的继承了 Object 类。
    * 5:任何对象都可以调用Object类中的方法。
    * 6:Object 类是所有的任何类的父类。(除了它自身)。
    * 7:Object 类中定义的方法是所有的对象都共有的方法,这些方法都是需要掌握。11个方法。3个重载。
    * 总结:Object 类 java 继承体系中 根类。
    *
    * Object 中定义的方法介绍:
    * 1:public String toString(): 获取当前对象的字符串表示形式。
    * 2:public boolean equals(Object o):判断两个对象是否相等。
    * 3:public int hashCode():返回对象的哈希码(内存地址)。
    * 4:public Class getClass():返回当前对象的 Class 对象。
    * 5:protected void finalize(): 对象的临终遗言方法。
    * 6:protected Object clone(): 复制对象。
    * 7:public void wait(): 让当前线程 在当前对象上等待。
    * 8:public void notify(): 唤醒在当前对象上等待的某一个线程。
    * 9:public void notifyAll():唤醒在当前对象上等待的所有的线程。
    *
    */
    public class TestMouseAndCat {

    public static void main(String[] args) {
    Cat tom = new Cat("汤姆",60);
    Mouse jerry = new Mouse("杰瑞",80);

    tom.catchMouse(jerry);
    }
    }
    //模拟猫抓老鼠,属性:姓名、iq。
    //猫的功能:抓老鼠。 老鼠:逃跑,死亡。使用封装实现。
    //子类型。
    class Cat extends Animal{
    public Cat() {
    }

    public Cat(String name, int iq) {
    super();
    setName(name);
    setIq(iq);
    }

    public void catchMouse(Mouse mouse){
    if(this.getIq() > mouse.getIq()){
    mouse.die();
    }else{
    mouse.run();
    }
    }
    }

    //子类型
    class Mouse extends Animal{
    public Mouse() {
    }
    public Mouse(String name, int iq) {
    super();
    setName(name);
    setIq(iq);
    }
    public void run() {
    System.out.println(this.getName() + "\t聪明机智,顺利的从猫爪下逃生了!");
    }
    public void die() {
    System.out.println(this.getName() + "\t傻乎乎的,被抓住吃掉了~~");
    }
    }


    //代码的问题:存在大量的冗余代码,定义一个单独的类,将公共的部分提取出来放到这个类中。让猫和老鼠复用这个类。
    //父类,猫和老鼠的父类型,两个子类共有的属性组成的类型。
    class Animal extends Object{
    private String name;
    private int iq;

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    public int getIq() {
    return iq;
    }

    public void setIq(int iq) {
    this.iq = iq;
    }
    }
  • 哪些成员不能被继承

    • 构造方法

    • 私有成员

    • class Animal{
      	//不能被子类继承。
      	private String name;
      	//只能被本包的子类继承。
      	int age;
      	//可以被所有的子类继承。
      	protected int weight;
      	//可以被所有的子类继承。
      	public void show(){}
      	//构造方法不能被子类继承。
      }
      
      class Cat extends Animal{
      	public Cat() {
      //		name = "";
      		age ++;
      	}
      	public void catchMouse(){}
      }
  • 方法重写 overwrite|override

    • 重写的注意的问题

    • package com.qf.inheritance;

      /**
      * 方法的重载:overload
      *
      * 方法的重写|覆盖:overwrite|override
      * 为何要重写:
      * 父类中的方法不能满足子类的需求,需要对方法重新定义。
      *
      * 如何重写:
      * 1:访问权限要大于等于父类中被重写的方法的权限。
      * 2:如果返回值类型是基本数据类型,那么必须一致。如果是引用数据类型,可以返回被重写的方法的返回类型的子类型。
      * 3:方法名必须一致。
      * 4:形参列表。必须一致,不一致就是重载。
      * 5:方法抛出的异常类型,子类在重写的时候,抛出的一场的类型要小于等于父类的。
      * 6:方法体:不一致。
      *
      */
      public class TestInheritance {

      public static void main(String[] args) {
      Dog dog = new Dog();
      dog.eat();
      }

      }

      class Animal{
      //不能被子类继承。
      private String name;
      //只能被本包的子类继承。
      int age;
      //可以被所有的子类继承。
      protected int weight;
      //可以被所有的子类继承。
      public void show(){}
      //构造方法不能被子类继承。

      Animal eat()throws NullPointerException{
      System.out.println("动物都是吃货!!");
      return new Animal();
      }
      }

      class Cat extends Animal{
      public Cat() {
      age ++;
      }
      public void catchMouse(){}

      Cat eat(){
      System.out.println("猫猫喜欢吃鱼!!");
      return new Cat();
      }
      }
  • super

    • 子类对象包含的内容

    • package com.qf.inheritance;
      /** 
      * 子类对象包含的内容:
      * 	包含了它所有的父类的实例成员变量,包括私有的成员变量。
      * 	还包含了子类中定义的成员变量。
      * 
      * super:超级的。
      * 	1:super 是java的关键字。
      * 	2:在子类的方法中使用。
      * 作用:
      * 	1:在子类中通过super. 可以访问父类被子类重写的方法。
      * 	2:在子类中通过super. 可以访问父类中被子类隐藏的成员变量。(情况很少)
      * 	3:在子类的构造方法的第一句,必须是使用 super(实参列表)调用父类的构造方法,以完成子类对象中包含的父类的实例成员变量的初始化工作。
      * 		1:任何子类中的构造方法,都必须隐式的或者显式的调用直接父类的构造方法通过super(实参列表).
      * 		2:隐式 的调用 父类的构造方法,只能调用它默认无参的构造方法。如果父类中没有默认无参的构造方法,那么在子类中必须显式调用。
      * 		3:这种调用super(...)必须在子类的构造方法的第一句完成。以实现先给父类的实例成员变量初始化,然后在给子类中定义的属性初始化。
      * 			子类对象的属性的初始化是有顺序的。按照继承体系从上到下初始化的。
      *
      */
      public class TestPerson {
      
      	public static void main(String[] args) {
      		Student tom = new Student(10,"tom","boy",100);
      		Student jerry = new Student(3,"jerry","boy",90);
      		
      		tom.show();
      		jerry.show();
      	}
      
      }
      
      class Person{
      	private int age;
      	private String name;
      	private String gender;
      	
      	public Person() {
      	}
      	public Person(int age, String name, String gender) {
      		this.age = age;
      		this.name = name;
      		this.gender = gender;
      	}
      	public int getAge() {
      		return age;
      	}
      	public void setAge(int age) {
      		this.age = age;
      	}
      	public String getName() {
      		return name;
      	}
      	public void setName(String name) {
      		this.name = name;
      	}
      	public String getGender() {
      		return gender;
      	}
      	public void setGender(String gender) {
      		this.gender = gender;
      	}
      }
      
      class Student extends Person{
      	private int score;
      	
      	public Student() {
      		//可以是隐式调用。
      		this(1,"a","b",100);
      	}
      	public Student(int age, String name, String gender,int score) {
      		super(age,name,gender);
      		this.score = score;
      	}
      	
      	public void show(){
      		System.out.println("name = " + getName() + "\tage = " +getAge() + "\tgender = "+getGender() + "\tscore = " +score);
      	}
      	
      }
  • 重写toString()

  • package com.qf.inheritance;
    /**
    * Object 的 方法:
    * public String toString(){
    * return getClass().getName()+"@"+Integer.toHexString(hashCode());
    * }
    * getClass().getName():当前对象类型的包名+类名
    * Integer.toHexString(hashCode()):
    * 得到当前对象的内存地址的十六进制字符串形式。
    * 返回该对象的字符串表示。通常,toString 方法会返回一个“以文本方式表示”此对象的字符串。
    * 结果应是一个简明但易于读懂的信息表达式。建议所有子类都重写此方法。
    *
    * 作用:得到当前对象在字符串标识形式。
    */
    public class TestObject {

    public static void main(String[] args) {
    Stu tom = new Stu("Tom",10,"boy");
    //将任意的数据转换为字符串,然后输出到标准输出设备上。
    //println 方法,对于对象,会在底层调用toString 方法,实现对象到字符串的转换。
    System.out.println(tom);//
    }
    }

    class Stu{
    private String name;
    private int age;
    private String gender;

    public Stu() {
    // TODO Auto-generated constructor stub
    }
    public Stu(String name, int age, String gender) {
    super();
    this.name = name;
    this.age = age;
    this.gender = gender;
    }
    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 String getGender() {
    return gender;
    }
    public void setGender(String gender) {
    this.gender = gender;
    }
    public String toString() {
    return "[姓名=" + name + ", 年龄=" + age + ", 性别=" + gender + "]";
    }
    }
  • 继承描述的关系-何时使用继承。

    • 继承表达的是一种 is-a 关系。

    • 只有子类和父类存在这样的关系的时候才可以使用继承,不然不能使用继承。

  • 子类对象构造过程

    • new 关键字向 jvm 申请内存。jvm 根据当前对象的类型以及它的所有的父类中定义的实例成员变量,分配对应的内存。并执行默认初始化。

    • 按照类的继承层次,上从到下,依次先给父类的实例成员执行声明处的赋值,然后调用父类的构造方法,接下来执行和上面同样的步骤,执行它的下一个父类,直到执行到子类自身结束。

  • 继承优缺点

    • 优点:代码复用、是实现多态的基础。

    • 缺点:

      • 继承中,如果父类发生了改变,那么可能会影响所有的子类。父类对于稳定性的要求非常高。

      • 如果要能继承父类中的成员,那么父类中的内容不能是私有的,有些时候继承会在一定程度上破坏类的封装性。

  • instanceof

    • package com.qf.inheritance;
      
      /**
       * instanceof:xx 是不是 谁的 实例对象。
       * 1:instanceof 是java的关键字。
       * 2:这是java的一个运算符。
       * 3:二元运算符,需要两个操作数。
       * 4:语法: 对象  instanceof 类型
       * 5:返回值是  boolean 值。
       * 6:作用:用来判断 左边 对象是否是右边的类型的实例。如果是 true,否则false。
       *
       * 结论:
       * 	子类对象是父类类型的实例。
       * 	任何对象都是Object类型的实例。
       * 
       * 使用限制:
       * 	对象的类型和右边的类型必须存在继承关系才可以使用。
       */
      public class TestInstanceof {
      	public static void main(String[] args) {
      		Person person = new Person();
      		Student student = new Student();
      		
      		System.out.println(person instanceof Person);//true
      		System.out.println(student instanceof Student);//true
      		
      		System.out.println(student instanceof Person);//true
      		System.out.println(student instanceof Object);//true
      		
      		System.out.println(person instanceof Student);//false
      		
      //		System.out.println(person instanceof A);
      	}
      }
      class A{}

7.17 多态

  • 多态概念

    • package com.qf.ploy;
      /**
       * 多态的概念:多态是一种能力,是一种父类引用指向子类对象,在运行期,会根据对象的实际类型调用,实际类型中重写父类的方法的能力。
       * 
       * 多态的三个必要条件:
       * 	1:继承
       * 	2:子类重写父类方法
       * 	3:父类引用指向子类对象。
       * 
       * 多态:对象的多种形态,通常是子类对象当做父类类型来使用。
       */
      public class TestAnimal {
      
      	public static void main(String[] args) {
      		int i = 10;
      		
      		Animal animal = new Animal();
      		animal.sound();
      		
      		Dog dog = new Dog();
      		dog.sound();
      		
      		//多态
      		Animal ani = new Dog();
      		ani.sound();
      	}
      }
      class Animal{
      	void sound(){
      		System.out.println("动物都会叫~~~");
      	}
      }
      class Dog extends Animal{
      	@Override
      	void sound() {
      		System.out.println("汪汪汪~~");
      	}
      	
      	void saveDoor(){}
      	
      }
      class Cat extends Animal{
      	@Override
      	void sound() {
      		System.out.println("喵喵喵~~");
      	}
      }
    •  

  • 多态的应用

    • 父类型做为参数

    • package com.qf.ploy;
      /**
       * 不同国家的人,去饭店吃饭。
       * 
       * 软件设计中的最重要的原则:开闭原则:对功能的扩展时候开放的,对源代码的修改是关闭的。
       * 
       * 多态的应用场景之一:最重要的应用的场景。
       * 	父类类型作为形参,传递的是子类对象。调用的是子类重写的方法。
       */
      public class TestHotel {
      
      	public static void main(String[] args) {
      		Hotel hotel = new Hotel();
      		
      		Chinese chinese = new Chinese();
      		Japanese japanese = new Japanese();
      		Indian indian = new Indian();
      		
      		hotel.showEat(chinese);
      		hotel.showEat(japanese);
      		hotel.showEat(indian);
      		
      		hotel.showEat(new American());
      		
      		hotel.showEat(new Italian());
      	}
      
      }
      //不同的国家的人的公共的父类。
      class People{
      	//国家名称。
      	private String nation;
      	
      	public People() {
      	}
      
      	public People(String nation) {
      		super();
      		this.nation = nation;
      	}
      
      	public String getNation() {
      		return nation;
      	}
      
      	public void setNation(String nation) {
      		this.nation = nation;
      	}
      	
      	//存在的意义就是为了呗子类重写,为了实现多态。
      	public void eat(){}
      }
      
      class Chinese extends People{
      
      	public Chinese() {
      		super("伟大的炎黄子孙");
      	}
      	
      	@Override
      	public void eat() {
      		System.out.println(getNation() + "\t使用筷子吃饭。。棒棒哒");
      	}
      }
      
      class Japanese extends People{
      	public Japanese() {
      		super("小日本");
      	}
      	
      	@Override
      	public void eat() {
      		System.out.println(getNation() + "\t吃生鱼片~~~");
      	}
      }
      
      class Indian extends People{
      	public Indian() {
      		super("印度阿三");
      	}
      	
      	@Override
      	public void eat() {
      		System.out.println(getNation() + "\t喜欢吃抛饼~~~");
      	}
      }
      
      class American extends People{
      	public American() {
      		super("美帝");
      	}
      	
      	@Override
      	public void eat() {
      		System.out.println(getNation() + "\t喜欢吃洋葱沙拉~~~");
      	}
      }
      
      class Italian extends People {
      	public Italian() {
      		super("意大利人");
      	}
      	
      	@Override
      	public void eat() {
      		System.out.println(getNation() + "\t喜欢吃意大利面~~~");
      	}
      }
      
      
      class Hotel{
      	private String name = "千峰大酒店";
      //	public void showEat(Chinese chinese){
      //		chinese.eat();
      //	}
      //	public void showEat(Japanese japanese){
      //		japanese.eat();
      //	}
      //	public void showEat(Indian indian){
      //		indian.eat();
      //	}
      //	public void showEat(American american){
      //		american.eat();
      //	}
          //多态
      	public void showEat(People people){
      		people.eat();
      	}
      }
    •  

    • 父类型作为方法的返回值

    • package com.qf.ploy;
      //定义了个用于创建不同的国家的人对象的工厂。
      //简单工厂设计模式。
      /**
      * 多态的场景-2:
      * 一个方法,声明的返回类型是父类类型,实际上返回的是子类对象。
      */
      public class Factory {

      //定义一个方法,用于创建不同国家的人。
      // public People createPeople(String className){
      // switch(className){
      // case "Chinese":
      // return new Chinese();
      // case "Japanese":
      // return new Japanese();
      // case "Indian":
      // return new Chinese();
      // case "Italian":
      // return new Italian();
      // case "American":
      // return new American();
      // }
      // return null;
      // }

      public People createPeople(String className){
      People people = null;
      switch(className){
      case "Chinese":
      people = new Chinese();
      break;
      case "Japanese":
      people =  new Japanese();
      break;
      case "Indian":
      people =  new Chinese();
      break;
      case "Italian":
      people =  new Italian();
      break;
      case "American":
      people =  new American();
      break;
      }
      return people;
      }
      }
  • 多态练习

  • 多态转型

    • instanceof 判断向下转型

    • package com.qf.ploy1;
      /**
      * 多态转型:
      *
      * 1: 自动向上类型转换:子类对象当做父类类型使用。
      * 2:强制向下类型转换,父类类型转换为子类类型来使用,需要使用 强转的 语法。
      * 只有需要访问子类特有的内容才有必要强转。
      */
      public class TestAnimal {

      public static void main(String[] args) {
      //基本数据类型中的自动向上类型转换。小类型当做大类型来使用。
      long l = 10;
      //基本数据类型中的强制向下类型转换。
      byte b = (byte)10000;

      //引用数据类型中的自动向上类型转换。 子类对象当做父类类型来使用,父类引用指向子类对象。
      Animal a = new Dog();
      a.sound();

      //通过一种特殊的语法,告诉编译器,这个a动物的确是一只dog。
      //多态中的强制向下类型转换。只有需要访问子类特有的内容的时候,才有必要向下强制类型转换。
      Dog dog = (Dog)a;
      dog.saveDoor();

      Animal cat = new Cat();
      //ClassCastException
      if(cat instanceof Dog){
      Dog dog1 = (Dog)cat;
      dog1.saveDoor();
      }
      }
      }

      class Animal{
      void sound(){
      System.out.println("动物都会叫~~~");
      }
      }

      class Dog extends Animal{
      @Override
      void sound() {
      System.out.println("汪汪汪~~");
      }

      void saveDoor(){
      System.out.println("狗狗会看门");
      }

      }

      class Cat extends Animal{
      @Override
      void sound() {
      System.out.println("喵喵喵~~");
      }
      }
    • 重写 equals

      • package com.qf.oop1;
        
        //需求:比较两个学生对象是否一样。
        /**
         * ==:比较,基本数据类型比较的是两个变量的值。
         * 引用数据类型使用  == 比较,比较的是两个对象的地址。
         * 
         * Object 定义了 equals 方法,就是用于比较两个对象是否相等的。
         * 默认实现是 比较 地址。
         *  public boolean equals(Object obj) {
                return (this == obj);
            }
            
               如果子类需要根据内容比较两个对象是否相等,那么需要子类重写该方法。
         *
         */
        public class TestEquals {
        
        	public static void main(String[] args) {
        		Student s1 = new Student("Tom", 10, "male");
        		Student s2 = new Student("Tom", 10, "male");
        		
        		System.out.println(s1 == s2);//false
        		
        		System.out.println(s1.equals(s2));//false
        	}
        
        }
        
        class Student{
        	private String name;
        	private int age;
        	private String gender;
        	
        	public Student() {
        	}
        
        	public Student(String name, int age, String gender) {
        		super();
        		this.name = name;
        		this.age = age;
        		this.gender = gender;
        	}
        
        	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 String getGender() {
        		return gender;
        	}
        
        	public void setGender(String gender) {
        		this.gender = gender;
        	}
        	
        	@Override
        	public boolean equals(Object obj) {
        		if (this == obj)
        			return true;
        		if (obj == null)
        			return false;
        		//当前对象的类型和obj的类型不同。
        		if (getClass() != obj.getClass())
        			return false;
        		
        		Student other = (Student) obj;
        		if (age != other.age)
        			return false;
        		if (gender == null) {
        			if (other.gender != null)
        				return false;
        		} else if (!gender.equals(other.gender))
        			return false;
        		if (name == null) {
        			if (other.name != null)
        				return false;
        		} else if (!name.equals(other.name))
        			return false;
        		
        		return true;
        	}
        	
        
        	//重写equals 方法。
        	public boolean equals1(Object obj) {
        		//特殊情况。
        //		obj 是个空对象。
        		if(obj == null)
        			return false;
        //		obj 和当前对象是同一个对象。
        		if(this == obj)
        			return true;
        		
        //		obj 必须是一个学生对象才有必要继续比较内容。
        		if(obj instanceof Student){
        			//比较内容。this 和 obj 比较内容。
        			Student s = (Student)obj;
        			if(this.age != s.age)
        				return false;
        			if(this.name != s.name)
        				return false;
        			if(this.gender != s.gender)
        				return false;
        				
        			return true;
        		}
        		return false;
        	}
        
        	@Override
        	public String toString() {
        		return "Student [name=" + name + ", age=" + age + ", gender=" + gender + "]";
        	}
        }

7.18 抽象类

  • abstract 的用法

  • package com.qf.abs;
    /**
     * 抽象类。
     * 
     * 抽象方法:
     * 	如果一个方法被 abstract 关键字修饰了,那么该方法称为抽象方法,抽象方法不能有方法体,不能被调用。
     * 	抽象方法的必须以分号结尾。
     * 	语法:[ abstract 返回值类型  方法名(形参列表); ]
     * 
     * 	如果一个类中有方法被声明了抽象方法,那么该类必须声明成抽象类。
     * 
     * 抽象类的特点:
     * 	1:抽象类中可以包含抽象方法。也可以没有定义抽象方法。
     * 	2:抽象类不能被实例化,不能创建抽象类的对象。
     * 	3:抽象类只能作为父类存在,只能 被继承。
     * 	4:抽象类中的抽象方法,要么在子类中被实现。implements,要么将子类声明成抽象类。
     *
     */
    public class TestAbstract {
    
    	public static void main(String[] args) {
    		new Person().play(new Drum());
    	}
    
    }
    
    //所有的乐器的父类
    abstract class Instrument{
    	//	sound 方法存在的意义是为了被子类重写的。
    	abstract void sound();
    	void test(){}
    }
    
    //乐器子类
    class Drum extends Instrument{
    	@Override
    	void sound() {
    		System.out.println("咚咚咚");
    	}
    	
    	@Override
    	void test() {
    	}
    }
    
    class Paino extends Instrument{
    	@Override
    	void sound() {
    		System.out.println("当当当");
    	}
    }
    
    class Person{
    	//	人演奏乐器,使用所有的子类类型作为形参。传递子类对象。
    	void play(Instrument instrument){
    		instrument.sound();
    	}
    }
    
    class Guita extends Instrument{
    
    	@Override
    	void sound() {
    		System.out.println();
    	}
    	
    }
    //没有抽象方法的抽象类
    abstract class A{
    	void test(){}
    }

7.19 static

  • 相关的概念

  • 静态成员特点

  • 何时使用static

  • package com.qf.static1;

    /**
    * static:
    * 1: static 是java的关键字。
    * 2:静态的意思。
    * 3:static 是用来修饰类成员的
    * 1:可以修饰类中的成员变量-->静态成员成员边量。
    * 2:修饰类中的成员方法-->静态成员方法。
    * 3:修饰静态代码块
    *
    * 4:静态成员变量的特点:
    * 1:静态成员变量的内存空间只有一份。
    * 2:静态成员变量的内存空间不依赖于任何对象。
    * 3:静态成员变量的内存空间在方法区。
    * 4:静态成员变量的内存空间依赖于所在的类,当类加载的时候给所有的静态成员变量分配内存。
    * 任何一个类只加载一次。静态成员变量分配内存也只有一次。
    * 5:静态成员变量除了可以通过对象访问之外,还可以通过类名直接访问。而且【建议通过类名来访问静态变量】。
    *
    * 5:什么样的变量可以定义为静态变量:
    * 1:希望所有的对象共享的数据。
    * 2:属于类型的属性。
    * 例子:所有的final修饰的变量一般都被定义为静态的。
    *
    * 6:静态成员方法特点
    * 1:可以通过对象调用。建议通过类名直接访问。
    * 2:工具方法一般都被定义为静态方法,方便使用。
    * 3:静态方法还可以用来访问本类的其他的静态成员。
    * 4:静态方法中【不能访问实例成员变量】,因为调用静态方法的时候,不能确定实例成员的内存是否已经分配了。
    * 5:静态方法中不能使用this。
    *
    */
    public class TestStatic {

    public static void main(String[] args) {
    //统计创建了多少个学生对象。
    new Student();
    Student student = new Student();

    System.out.println(Student.count);//2
    System.out.println(student.count);//2

    student.test();
    Student.test();
    }
    }

    class Student{
    static final int MAX_AGE = 60;
    //实例成员变量。
    private String name;
    private int age;
    //静态成员变量|类变量
    static int count;

    public Student() {
    count ++;
    }

    static void test(){
    // age++;
    // show();
    // this.age++;
    count++;
    }
    void show(){}
    }

7.20 代码块(**)

package com.qf.static1;

import com.qf.util.MyUtil;

/**
* 代码块:code block
* 程序中的一对大括号。
*
* 分类:
* 1:局部代码块。方法内的一对大括号。
* 作用:将局部变量的作用域范围控制的更小,在局部代码块中定义的局部变量的作用域只在代码块中作用。
* 2:构造块:类体中的一对大括号。
* 作用:对实例成员变量初始化。和构造方法的作用一致。
* 说明:编译之后,所有的构造块全部消失,构造块中的代码,都放到构造方法中去执行了。
* 3:静态代码块:
* 类体中的一对大括号,使用 static 修饰。
* static{}
* 静态代码块特点:
* 1:只能被执行一次。
* 2:所在的类加载的时候被执行一次。
*
* 作用:
* 1:初始化静态成员。
* 2:将一些只执行一次的代码在静态代码块中执行。
*  
*/
public class TestBlock {
public TestBlock() {
System.out.println("TestBlock");
}
static int num;
// 静态代码块。
static{
System.out.println("static block");
num = MyUtil.random(0, 100);
}
private int age;
// 构造块。
{
age = 10;
System.out.println("age = " + age);
}
public static void main(String[] args) {
new TestBlock();
new TestBlock();
}
}

 

7.21 类加载过程

  • 类加载的触发时机

    • 创建类的对象

    • 创建子类对象

    • 访问类的静态成员

    • 使用Class.forName(全限定名)

  • 类的加载过程

    • 装载

      • 通过类的全名,获取类的二进制数据流。

      • 解析类的二进制数据流为方法区内的可以识别的数据结构(java类模型)。

    • 链接

      • 验证

        • 保证加载的字节码是合法的。

      • 准备

        • 为类的静态变量分配内存,并执行默认初始化。

      • 解析

        • 将代码中的符号引用转换为地址引用

    • 初始化

      • 执行类中的静态成员的声明处的赋值。

      • 执行静态代码块中的内容

      • 类加载完毕。

  • 继承中的类加载执行顺序?

    • 先加载最上层的父类,从上到下依次加载。

7.22 final 总结

  • package com.qf.static1;
    /**
     * final 总结:
     * 	1:java的关键字。
     * 	2:可以用来修饰变量,修饰方法,修饰类。
     * 	3:修饰变量,变量成为终态变量。常量。只能被赋值一次。
     * 	4:修饰方法:不能被子类重写。
     * 	5:修饰类:终态类,不能有子类,不能被继承。
     * 		断子绝孙类。
     *
     */
    public class TestFinal {
    
    	public static void main(String[] args) {
    		
    	}
    }
    final class Person{
    	final void test(){}
    }
    class Stu extends Person{
    }
    
  •  

7.23 阶段若干问题

1. 抽象类中是否一定包含抽象方法?
  • 不一定,可以有也可以没有。

2. 有抽象方法的类是否一定是抽象类?
  • 是的。

3. 抽象方法是否可以使用final 修饰?
  • abstract 关键字 和 final 是互斥的。

4. final 是否可以修饰抽象类?
  • abstract 关键字 和 final 是互斥的。

5. 私有方法是否可以使用abstract修饰?
  • private 和 abstract 也是互斥的。私有方法天然具有final 属性。

6. 静态的方法是否可以被重写?
  • 只有实例方法才能被重写。

7. abstract是否可以修饰静态方法?
  • abstract 和 static 也是互斥的。

8. 静态方法是否可以实现多态?
  • 不能实现多态。

9. 类中的实例成员变量是否可以实现多态?
  • 不能实现多态

10. 抽象方法的深层理解
  • 一个抽象方法就是一个规则,父类定义了抽象方法的规则,给所有的实现的子类制定的。子类必须按照父类的规则去实现抽象方法。

11. 总结:多态是对象的多态,是针对对象的功能的多态。只针对实例方法。

7.23 接口

1. 概念:一组规范的功能的描述。
2. 语法
3. 接口的简单应用
4. 接口在多态中的简单使用
5. 接口案例 Fly
package com.qf.inter;
/**
* 举办一个飞行大赛。
* 所有会飞行的对象都能参加。
* 需要使用一个数组来管理所有的参赛者。
* 参加的对象:飞机、超人、麻雀、石头。
*/
public class TestFly {

public static void main(String[] args) {
Flyable[] flyables = new Flyable[4];
flyables[0] = new Plane();
flyables[1] = new SuperMan();
flyables[2] = new Bird();
flyables[3] = new Stone();

for (int i = 0; i < flyables.length; i++) {
flyables[i].fly();
}
}

}
interface Flyable{
void fly();
}

class Plane implements Flyable{

@Override
public void fly() {
System.out.println("飞机屁股冒烟飞!!");
}

}

class SuperMan extends Person implements Flyable{

@Override
public void fly() {
System.out.println("内裤外传,双手握拳飞向了氪星球!!");
}

}

class Animal{}

class Bird extends Animal implements Flyable{

@Override
public void fly() {
System.out.println("小鸟扑棱这翅膀飞!!");
}

}

class Stone implements Flyable{

@Override
public void fly() {
System.out.println("石头被人用力一扔,在空中划出一道美丽的弧线!!");
}

}
package com.qf.inter;


public class TestLogin {

public static void main(String[] args) {
Loginable loginable = new LoginImpl();
int result = loginable.registe("", "");
}

}

//组长定义接口。实现登陆注册的模块。
interface Loginable{
/**
* 实现登陆功能。
* @param name 登陆的用户名
* @param pwd 登陆的密码。
* @return 如果用户名不存在,返回-1,如果密码不正确返回-2。登陆超时,返回-3,登陆成功返回1.
*/
int login(String name,String pwd);

/**
* 实现注册功能。
* @param name 注册的用户名
* @param pwd 注册的密码
* @return 如果用户名不合法返回-1 ,密码不合法 返回-2.用户名已经存在 返回-3,请求超时 返回-4,注册成功返回 1.
*/
int registe(String name,String pwd);
}

//有人写实现类。
class LoginImpl implements Loginable{

@Override
public int login(String name, String pwd) {

return 1;
}

@Override
public int registe(String name, String pwd) {
// TODO Auto-generated method stub
return 1;
}
}

 

6. 接口案例 USB
  • 早期的鼠标和键盘

  • 接口回调


  • public class TestInterface {

    public static void main(String[] args) {
    Mouse mouse = new Mouse();
    Computer computer = new Computer();

    computer.load(mouse);
    computer.load(new Fun());
    }
    }

    //描述插头规范。
    interface UsbPlug{

    public static final int WIDTH = 10;
    public static final int HEIGHT = 3;

    // 功能,可以从usb插槽中获取电,让连接插头设备运转。
    void run();
    }
    //描述usb插槽规范
    interface UsbSocket{

    public static final int WIDTH = 10;
    public static final int HEIGHT = 3;

    // 可以装载插头。
    void load(UsbPlug plug);
    }

    //鼠标实现了插头的规范。
    class Mouse implements UsbPlug{
    @Override
    public void run() {
    System.out.println("鼠标运转起来了!!");
    }
    }

    class Computer implements UsbSocket{

    @Override
    public void load(UsbPlug plug) {
    plug.run();
    }
    }

    class Fun implements UsbPlug{
    @Override
    public void run() {
    System.out.println("小风扇转起来了,吹出了凉爽的风");
    }
    }
  •  

7. 继承和实现的语法总结
  • package com.qf.inter;
    /**
    * 接口:interface。
    * 1:概念:一组规范的功能的描述。
    * 2:语法:
    * 权限修饰符 interface 接口名{
    * //public static final 的变量
    * //public abstract 的方法。
    * }
    * 3:public static final 可以省略。public abstract 也可以省略。
    * 4:【接口是面向功能开发的。】
    * 如果想把某些功能添加给某种类型,而这些功能不是该类型特有的,那么应该借助接口实现。
    * 5:【接口是用来描述规范的,如果希望某种类型遵守某个规范。使用接口定义规范,让类型去实现规范。】
    * 6:使用接口的语法:一个类可以实现多个接口。
    * class 类名 implements 接口名1,接口名2.....{}
    * 接口是实现的类的父接口。
    * 一个类可以有一个直接的父类,和多个直接的父接口。
    * 7:接口同样也可以实现多态,而且有接口的地方一定有多态。
    * 8:java不支持多继承,可以实现多个接口,弥补了不支持多继承的缺陷。
    * 9:继承表达的是一种 is-a 的关系。实现接口表达的是has-a 的关系。
    * 10:接口之间也可以继承。还可以多继承接口。
    * interface A extends Fightable,Driveable{}
    * 11:接口可以实现设计和实现相分离。
    *
    */
    public class TestInterface {

    public static void main(String[] args) {
    Person person = new Student();

    Fightable fightable = new Student();
    System.out.println(new Student() instanceof Fightable);//true
    System.out.println(new Student() instanceof Driveable);//true
    }

    }

    class Person {}

    class Student extends Person implements Fightable,Driveable{

    @Override
    public void drive() {
    }

    @Override
    public void fight() {
    }
    }

    interface Fightable{
    void fight();
    }
    interface Driveable{
    void drive();
    }
    interface A extends Fightable,Driveable{}
8. 常量接口和【标记接口】
  • Cloneable

  • Serializable

  • package com.qf.inter;

    /**
    * 常量接口:
    * 接口中只有常量。将项目中的所有的常量通过一个接口来管理。方便维护。使用接口名直接调用。(了解)
    * 标记接口:(掌握)
    * 接口中什么都没有。
    *
    * JDK 提供了2个标记接口:
    * java.lang.Cloneable
    * 只有实现了该接口的类,才能被克隆。
    * java.io.Serializable
    * 只有实现了该接口的类,才能被序列化。
    */
  •  

9. 接口总结
10. 自定义内部比较器和外部比较器
package com.qf.comparable;

import java.util.Arrays;

import com.qf.util.MyUtil;

/**
* 对一个学生数组排序。
*/
public class TestComparable {

public static void main(String[] args) {
test();
}

private static void test() {
String[] names = {"义鹏龙","马紫航","季程","王翔","王斯盈","张恒","刘伟龙","孙乐春","宋鹏超",
"杨添龙","刘李强","殷江涛","景蕊鑫","刘冰","王宸","李冠","李城锟","胡开畅","杨健",
"任江华","许凯","杨春星","李云","高宇","张帅","张颖涛","赵鸿威","章鑫","林洋","张舜斌",
"朱映正","王洪勇","姚雪丽","陈芊池","侯佳伟","孙浩","樊旺","刘德信","张晨光",
"张致豪","王佳欣","杰伟航","刘寅玉","刘付达","杨立航","赵梓茗",
"何东虎","杨东升","张战雄","王明磊"};
//使用一个学生数组管理班级的所有的学生。
Student[] students = new Student[names.length];
//对每个元素进行初始化。
for (int i = 0; i < students.length; i++) {
int age = MyUtil.random(18, 25);
int score = MyUtil.random(60, 101);
students[i] = new Student(names[i], age, score);
}

sort(students, new AgeAndScoreCompartor());
sort(students);

System.out.println(Arrays.toString(students));



}

//使用内部比较器接口实现学生对象之间的比较。
public static void sort(Student[] students){
for(int i=0;i<students.length-1;i++){
int minIndex = i;
for(int j=i+1;j<students.length;j++){
// if(students[j].getScore() < students[minIndex].getScore()){
// minIndex = j;
// }
if(students[j].compareTo(students[minIndex]) < 0){
minIndex = j;
}
}

if(i != minIndex){
Student temp = students[i];
students[i] = students[minIndex];
students[minIndex] = temp;
}
}
}

// 使用外部比较器对数组排序。
public static void sort(Student[] students,Comparator com){

for(int i=0;i<students.length-1;i++){
int minIndex = i;
for(int j=i+1;j<students.length;j++){
// if(students[j].compareTo(students[minIndex]) < 0){
// minIndex = j;
// }
if(com.compare(students[j], students[minIndex])<0){
minIndex = j;
}
}

if(i != minIndex){
Student temp = students[i];
students[i] = students[minIndex];
students[minIndex] = temp;
}
}
}

}


class Student implements Comparable{
private String name;
private int age;
private int score;

public Student() {
}

public Student(String name, int age, int score) {
super();
this.name = name;
this.age = age;
this.score = score;
}

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 int getScore() {
return score;
}

public void setScore(int score) {
this.score = score;
}

@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", score=" + score + "]\n";
}

@Override
/**
* 当前对象和o进行比较。
* @param o
* @return 如果当前对象比o大,返回正整数。如果比o小,返回负整数,相等返回0.
*
* 年龄的升序,分数的降序。
*/
public int compareTo(Object o) {
Student s1 = (Student)o;
// if(this.score > s1.score)
// return 1;
// if(this.score < s1.score)
// return -1;
// return 0;
// return s1.score - this.score;

int result = this.age - s1.age;
if(result == 0){
return s1.score - this.score;
}
// 年龄不同。
return result;
}

}


//内部比较器接口,可以让对象拥有一个内部比较的功能。
interface Comparable{
/**
* 当前对象和o进行比较。
* @param o
* @return 如果当前对象比o大,返回正整数。如果比o小,返回负整数,相等返回0.
*/
int compareTo(Object o);
}

//外部比较器接口。
interface Comparator{
/**
* 比较 两个对象 的大小关系。
* @param o1 待比较的对象1
* @param o2 待比较的对象2
* @return 如果o1比o2大,返回正整数。,小返回负整数,相等返回0.
*/
int compare(Object o1,Object o2);
}


//年龄的降序,分数的升序排序。
class AgeAndScoreCompartor implements Comparator{

@Override
public int compare(Object o1, Object o2) {
Student s1 = (Student)o1;
Student s2 = (Student)o2;

int result = s2.getAge() - s1.getAge();
if(result == 0){
return s1.getScore()-s2.getScore();
}
return result;
}

}
11. jdk 内置的比较器
package com.qf.comparable;

import java.util.Arrays;

import com.qf.util.MyUtil;
/**
* 如果想使用 Arrays.sort(Object[] os)方法对一个对象数组排序,那么该数组的元素的类型必须实现 java.lang.Comparable.
*
* 如果使用 Arrays.sort(Object[] os,java.util.Comparator com) 需要定义一个Comparator 实现的子类,在子类中指定你的排序规则。创建子类的对象,作为实参使用。
*
* 总结:
* jdk 提供内部比较器的实现比较简单。实现内部比较器接口,按照接口的规则实现 compareTo 方法即可。但是只能指定一种规则。
* 外不比较器,还需要单独定义比较器接口的子类,在子类中指定排序规则。实现稍微麻烦,但是可以针对多种排序给出不同的子类实现即可。
*
*/

public class TestSort {


public static void main(String[] args) {
test();
}

private static void test() {
String[] names = {"义鹏龙","马紫航","季程","王翔","王斯盈","张恒","刘伟龙","孙乐春","宋鹏超",
"杨添龙","刘李强","殷江涛","景蕊鑫","刘冰","王宸","李冠","李城锟","胡开畅","杨健",
"任江华","许凯","杨春星","李云","高宇","张帅","张颖涛","赵鸿威","章鑫","林洋","张舜斌",
"朱映正","王洪勇","姚雪丽","陈芊池","侯佳伟","孙浩","樊旺","刘德信","张晨光",
"张致豪","王佳欣","杰伟航","刘寅玉","刘付达","杨立航","赵梓茗",
"何东虎","杨东升","张战雄","王明磊"};
//使用一个学生数组管理班级的所有的学生。
Stu[] students = new Stu[names.length];
//对每个元素进行初始化。
for (int i = 0; i < students.length; i++) {
int age = MyUtil.random(18, 25);
int score = MyUtil.random(60, 101);
students[i] = new Stu(names[i], age, score);
}

//使用jdk提供的内部比较器接口实现排序。
// Arrays.sort(students);
//使用jdk提供的外部比较器接口实现排序。
Arrays.sort(students, new ScoreComparator());

System.out.println(Arrays.toString(students));

}
}

//定义一个外部比较器接口的实现来,指定外部比较器的排序的规则。
class ScoreComparator implements java.util.Comparator{

@Override
public int compare(Object o1, Object o2) {
Stu s1 = (Stu)o1;
Stu s2 = (Stu)o2;
return s2.getScore()-s1.getScore();
}

}

class Stu implements java.lang.Comparable{
private String name;
private int age;
private int score;

public Stu() {
}

public Stu(String name, int age, int score) {
super();
this.name = name;
this.age = age;
this.score = score;
}

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 int getScore() {
return score;
}

public void setScore(int score) {
this.score = score;
}

@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", score=" + score + "]\n";
}

@Override
/**
* 当前对象和o进行比较。
* @param o
* @return 如果当前对象比o大,返回正整数。如果比o小,返回负整数,相等返回0.
*
* 年龄的升序,分数的降序。
*/
public int compareTo(Object o) {
Stu s1 = (Stu)o;

int result = this.age - s1.age;
if(result == 0){
return s1.score - this.score;
}
// 年龄不同。
return result;
}
}
12. jdk1.8 接口调整
  • public static

  • public default

  • package com.qf.comparable;

    public class TestJDK18 {

    public static void main(String[] args) {
    MyInter.hello();
    }
    }
    interface MyInter{
    public static final int MIN = 10;
    public abstract void test();

    // jdk1.8 中,接口可以添加默认实现的方法。
    public default void show(){
    System.out.println();
    }
    // jdk1.8 中,接口可以添加静态的方法。
    public static void hello(){}
    }
13. 特殊类介绍(**)
  • 内部类

  • package com.qf.inner;

    import com.qf.inner.Body.Heart;

    /**
    * 内部类:inner class
    *
    * 分类:
    * 1:普通成员内部类。(**)
    * 2:静态成员内部类。(**)
    * 3:局部内部类()
    * 4:匿名内部类(***)
    *
    * 1:普通成员内部类
    * 特点:
    * 1:定义在一个类的内部的类。
    * 2:可以使用四种访问权限修饰符来修饰类。
    * 3:内部类可以访问外部类的私有成员。外部类也可以访问内部类的私有成员。
    * 4:普通成员内部类和外部类的关系,是一种包含关系。如果内部类是私有的,对于其他的外部类都是隐藏的。
    * 5:必须先创建外部类的对象,才能创建内部类的对象。普通成员内部类的对象是依赖于外部类的对象。
    * 6:内部类编译之后的名字:Body$Heart.class
    *
    */
    public class TestNormalInner {

    public static void main(String[] args) {
    Body body = new Body();
    //创建内部类的对象的方式
    Heart heart = body.new Heart();
    Heart heart2 = body.getHeart();
    Heart heart3 = new Body().new Heart();
    }
    }

    //外部类。
    class  Body{
    private int weigth;
    private int size;

    public Body() {
    new Heart().size ++;
    }
    public Heart getHeart(){
    return new Heart();
    }
    //普通成员内部类
    public class Heart{
    private int size;
    public Heart() {
    weigth ++;
    size ++;
    Body.this.size ++;
    }
    void show(){}
    }
    }
  • package com.qf.inner;

    import com.qf.inner.Outer.Inner;

    /**
    * 静态成员内部类。
    *
    * 特点:
    * 1:不需要创建外部类的对象,就能创建内部类的对象。
    * 2: 只能访问外部类的静态成员,不能访问外部类的实例成员。
    */
    public class TestStaticInner {

    public static void main(String[] args) {
    Inner inner = new Outer.Inner();
    }
    }
    class Outer {
    private int age;
    // 静态成员内部类。
    static class Inner{
    public Inner() {
    // age ++;
    }
    }
    }
  • package com.qf.inner;
    /**
    * 局部内部类:
    * 在方法中定义的类,该类只能在当前方法中使用。
    *
    */
    public class TestLocalInnerClass {

    public static void main(String[] args) {
    int i = 10;

    class A{
    void test(){
    System.out.println(10);
    // i++;
    }
    }
    A a = new A();
    a.test();
    }
    }
  • package com.qf.inner;

    import java.util.Comparator;

    /**
    * 匿名内部类:
    * 1:匿名内部类的本质是继承或者实现了某个接口的【匿名子类对象】。
    * 2:使用的场景:
    * 不想创建某一个类的子类或者实现某个接口的子类,但是还想得到该类或者是接口的子类对象。
    */
    public class AnoyClassTest {

    public static void main(String[] args) {
    // 继承一个普通的类。得到 Test 的匿名子类对象。
    Test t = new Test(){
    @Override
    void test() {
    System.out.println("我是test 重写的方法");
    }
    };
    t.test();

    // 继承一个抽象类,获得抽象类的匿名子类对象。
    AsbTest at = new AsbTest(){
    @Override
    void test() {
    System.out.println("这是重写的方法");
    }
    };
    at.test();

    // 实现一个接口的匿名子类对象。
    Comparator com = new Comparator(){
    public int compare(Object o1, Object o2) {
    return 0;
    }
    };
    }
    }

    class Test{
    void test(){
    }
    }
    abstract class AsbTest{
    abstract void test();
    }
  •  

14. 枚举类

 

15. 面向对象的设计原则
  • 总则:开闭原则

  • 单一职责原则

  • 里氏替换原则

  • 依赖倒置原则

  • 接口隔离原则

  • 迪米特法则(最少知道原则)

  • 合成复用原则

    • 组合优于继承

 

总结

  • 方法的定义形式:

    • [修饰符] 返回类型 方法名(形参列表) {}

  • 方法重载:同一个类的内部,方法名字相同,参数列表不同。

  • return:

  • 三种内存

  • 断点调试 掌握

  • 包名规范:全部小写

  • 类型:class

    • 自定义的类

    • jdk 提供的类

      • Scanner

      • Arrays

      • Math

      • System

    • 第三方的公司提供的类。

    • 对对象的抽象的描述。

    • java 所有的代码都是以类的形式组织的。

    • 一个类中:属性就是数据,方法就是要处理的数据的。

    • 类的构成:

      • 成员变量

      • 成员方法

      • 构造方法

  • 对象 Object

    • 对象就是数据。

    • 类的实例。

  • 根据需求定义不同的类,创建具有不同功能和属性的对象,然后通过对象之间的相互作用实现最终的需求。

  • 类型和对象的关系:类型是描述对象的、对象的类型的一个实例的展示。

  • 面向对象、面向过程对比。

  • 类的语法

  • 构造方法:

    • 构造器

    • 用来初始化对象属性。

  • 对象创建过程:

    • 类加载

    • 在堆内存分配空间,对属性执行默认初始化。

    • 执行属性声明处的赋值

    • 执行构造方法

    • 返回对象的地址。

  • 类体的成员

    • 成员变量

    • 成员方法

    • 构造方法

 

 

 

 

posted @   ITboy搬砖人  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示