Java学习笔记05_(面向对象)(全是干货)

第四章 Java面向对象
课程内容
1、面向对象和面向过程
2、类和对象
3、成员变量和局部变量
4、方法的重载
5、构造方法及重载
6、this
7、static
8、package和import
9、继承
10、重写
11、子类对象的内存结构图
12、super
13、equals
14、组合composite
15、封装
16、继承和封装
17、多态
18、向上、向下转型
19、简单工厂模式
20、final
21、抽象类
22、接口
23、内部类和匿名内部类
24、垃圾回收机制

一、面向对象编程和面向过程编程(B)
1.1、面向对象和面向过程的比较
面向过程 面向对象
区别 事物比较简单,可以用线性的思维去解决 事物比较复杂,使用简单的线性思维无法解决
共同点 面向过程和面向对象都是解决实际问题的一种思维方式

二者相辅相成,并不是对立的。
解决复杂问题,通过面向对象方式便于我们从宏观上把握事物之间复杂的关系、方便我们分析整个系统;具体到微观操作,仍然使用面向过程方式来处理。

1.2、面向对象和面向过程举例
参考PPT:JAVA面向对象编程_enbo.pptx
二、类和对象
2.1、类/对象的概念

对象:是具体的事物。
类:是对对象的抽象(抽象:抽出相似的部分)

先有具体的对象,然后抽象各个对象之间象(相似)的部分,归纳出类,通过类再认识其他具体对象。
抽象:
 把相同的或相似的对象归为一类的这个过程就是抽象,所以,抽象就是分析问题的方法;

抽象的基本原则:
 只关心主要问题,而不关心次要问题;
 只关心主要矛盾,而不关心次要矛盾;
 只关心相同的东西,而不关心不同的东西;
 只关心问题是什么,能够完成什么,而不关心怎样去完成。

注意:抽象的过程其实就是面向对象编程的核心思想。

示例:
举例说明:
创建一个类: Person.java (吃饭、睡觉、自我介绍)
类的内容:
(1)静态特征 – 属性(name\age\sex)
(2)动态行为 – 方法(eat\sleep\introduce)
如何使用类: TestPerson.java
/**

  • Person类

  • 1.类和对象的定义

    • 类(class) Person TestPerson String System
    • 对象(Object instance实例) xm xh
    • 类的抽象的,对象时具体的,是类的实例化
    • 类好比是模板,模具,图纸,对象就是按照模板,模具,图纸生产的具体的产品。
    • 类可以分为两大类:系统类String System 用户自定义类 Person TestPerson
    • 类的组成部分:静态的特征(成员变量) 动态的行为(成员方法),[构造方法,代码块,内部类]
  • 2.类的成员变量

    • String name;//姓名
    • int age;//年龄
    • String sex;//性别
    • 成员变量也叫属性field attribute,均指静态的特征
    • 作用范围:至少当前类
    • 所有的成员变量都有默认值:int 0,double 0.0,boolean false,char \u0000,引用类型 null
    • 还可以在定义变量的时候就赋值
    • 语法格式
    • [private] String name[=“无名氏”];
    • 权限修饰符 变量的数据类型 变量名 初始值
  • 3.类的成员方法

    • 成员方法:method,指动态的特征
    • 方法是功能的模块,是功能的封装,在某些语言中称为函数
    • 方法作用
      • 1.封装了某些功能,用户只要调用方法名即可,不需要了解内部细节,降低了使用的难度
      • 2.避免了代码的重复
    • 语法格式
      • public void sleep(String address){System.out.println(name +" sleeping at"+address);}
      • 权限修饰符 返回值类型 方法名 (参数列表){ 方法体}
      • void表明没有返回值,但是不可以省略
      • 参数可以0个,1个或者多个
  • 4.如何创建对象

    • Person xm =new Person();
    • Scanner input = new Scanner(System.in);
    • Person xm;//定义了一个引用变量(对象)
    • xm = new Person();//为对象在内存中分配空间
  • 5.如何调用类的成员变量和成员方法

    • 对象名.变量名
    • xm.name=“小明”;
    • 对象名.方法名
    • xm.sleep(“宿舍”);
      String info = xm.introduce();
    • 注意:同一个类中可以直接访问成员变量和成员方法
      /
      public class Person {
      //静态的特征:名词
      String name=“无名氏”;//姓名
      int age;//年龄
      String sex;//性别
      //动态的行为:动词
      /
    • 吃饭
      /
      public void eat(){
      System.out.println(“eating every day…”);
      //sleep(“宿舍”);
      //return;
      }
      /
    • 睡觉
      /
      public void sleep(String address){
      System.out.println(name +" sleeping at"+address);
      return;
      }
      /
    • 自我介绍
      /
      public String introduce(){
      //System.out.println(“姓名:”+name+",年龄:"+age+",性别:"+sex);
      return “姓名:”+name+",年龄:"+age+",性别:"+sex;
      }
      }
      /
      *
  • 6.对象的内存分配结构图

  • 明确:定义类不会分配空间,创建对象时才会分配空间

  • 涉及的内存空间包括栈内存(stack)和堆内存(heap)

  • 基本类型变量的存储只涉及 栈内存 局部变量

  • 引用类型变量的存储涉及 栈内存和堆内存

  • 栈内存中存放的是对象的引用变量 xm xh

  • 堆内存中存放的是对象的具体数据 name age sex

  • 也可以这么总结

  • 栈内存中存放的是局部变量(方法中定义的变量)

  • 堆内存中存放的是成员变量(类中定义的变量)
    */
    public class TestPerson {
    String name;
    public static void main(String[] args) {
    //创建一个人:小明
    //int n = 5;
    int n;
    n=5;
    //Person xm =new Person();
    Person xm;
    xm = new Person();
    xm.name=“小明”;
    xm.sex=“男”;
    xm.age=19;
    xm.eat();
    xm.sleep(“宿舍”);
    String info = xm.introduce();
    System.out.println(info);

    //创建又一个人:小红
    Person xh = new Person();
    xh.name=“小红”;
    xh.sex=“女”;
    xh.age=18;
    //String info2 =xh.introduce();
    //System.out.println(info2);
    System.out.println(xh.introduce());
    xh.eat();
    xh.sleep(“家里”);
    }

}

2.2、类/对象的总结
(1)类和对象的定义

  • 类(class) Person TestPerson String System
  • 对象(Object\instance实例) xm xh
  • 类是抽象的,对象是具体的,是类的 实例化
  • 类好比是模板,模具,图纸,对象就是按照模板,模具,图纸生产的具体的产品.
  • 类可以分为两大类:系统类String System 用户自定义类 Person TestPerson
  • 类的组成部分:静态的特征(成员变量) 、动态的行为(成员方法),[构造方法,代码块,内部类]

(2) 类的成员变量 (java是强类型语言)

  • String name;//姓名
  • int age;//年龄
  • String sex;//性别
  • 成员变量也叫属性field attribute,均指静态的特征
  • 作用范围:至少当前类
  • 所有的成员变量都有默认值:int 0,double 0.0,boolean false,char \u0000,引用类型 null
  • 还可以在定义变量的时候就赋值,即 初始值。
  • 语法格式
  • [private] String name[=“无名氏”];
  • 权限修饰符 变量的数据类型 变量名 初始值

(3)类的成员方法

  • 成员方法:method,指动态的特征
  • 方法是功能模块,是功能的封装,在某些语言中称为 函数
  • 方法作用
  • 1.封装了某些功能,用户只要调用方法名即可,不需要了解内部细节,降低了使用的难度
  • 2.避免了代码的重复
  • 语法格式
    public void sleep(String address){System.out.println(name +" sleeping at"+address);}
    权限修饰符 返回值类型 方法名 (参数列表){ 方法体}
  • void表明没有返回值,但是不可以省略
  • 参数可以0个,1个或者多个

(4)如何创建对象

  • Person xm = new Person();
  • Scanner input = new Scanner(System.in);
  • Person xm;//定义了一个引用变量(对象)
  • xm = new Person();//为对象在内存中分配空间

(5)如何调用类的成员变量和成员方法

  • 对象名.变量名
  • xm.name=“小明”;
  • 对象名.方法名
  • xm.sleep(“宿舍”);
    String info = xm.introduce();

注意:同一个类中可以直接访问 成员变量 和 成员方法

(6)对象的内存分配结构图(下节讲)

2.3、对象的内存分配图
明确:定义类不会分配内存空间,创建对象时才会分配内存空间。

  • 涉及的内存空间包括: 栈内存(stack)和 堆内存(heap)

  • 基本类型变量的存储只涉及 栈内存

  • 引用类型变量的存储涉及 栈内存 和 堆内存

  • 栈内存中存放的是对象的 引用变量 xm xh

  • 堆内存中存放的是对象的 具体数据 name age sex

  • 也可以这么总结:

  • 栈内存中存放的是 局部变量(方法中定义的变量)

  • 堆内存中存放的是 成员变量(类中定义的变量)

示例:基于TestPerson.java代码画出内存结构图

练习:
设计一个类,并且给出类对应的属性和方法,同时给出相应的测试类。(画出相应的内存图)
类Dog
(静态特征:color、weight、age、type)
(动态行为: eat()、sleep()、kanJian())

2.4、方法的调用
需求:定义计算器类 – 使用计算器完成加法运算
代码演示 – 画图

方法调用的过程:
1.将实参赋给对应的形参
2.执行方法
3.返回方法的返回值

总结:
形参和实参要求个数相同,类型匹配,对应参数名称是否相同对结果没有任何影响。

示例:计算器
/**

  • 计算器类

  • 使用计算器完成加法运算

  • 1.复习类和对象

  • 2.方法的调用过程

  • public int add(int num1,int num2){} 方法的定义 方法的声明 num1,num2 形式参数 形参

  • int result = calc.add(num1,num2); 方法调用 num1,num2 实在参数 实参

  • 形参和实参要求个数相同,类型匹配,对应参数名称是否相同对结果没有任何影响

  • 方法调用的过程

    • 1.将实参赋给对应的形参
    • 2.执行方法
    • 3.返回方法的返回值

    画方法调用的内存结构图

  • 3.局部变量和成员变量区别

  • 1.定义位置不同 局部变量定义在方法中(包括形式参数) 成员变量定义在类中

  • 2.作用范围不同 局部变量的作用范围是当前方法 成员变量的作用范围最小当前类

  •  如果成员变量和局部变量同名,局部变量优先级别高
    
  • 3.初始值不同:局部变量没有初始值 成员变量有初始值

  • 4.在内存中位置不同 局部变量在栈内存,成员变量在堆内存中

    画内存结构图
    */
    public class Calculator {
    String brand=“联想计算器”;
    double price;
    //int num1;
    public static void main(String[] args) {
    int num1;
    num1=20;
    int num2 = 30;
    //int result = num1+num2;//不仅知道干什么,还要知道怎么干
    Calculator calc = new Calculator();
    int result = calc.add(num1,num2);//只要知道干什么即可
    System.out.println(result);
    }

    public int add(int num1,int num2){
    int result;
    result = num1+num2;
    System.out.println(price);
    return result;
    }
    }
    内存结构图:

2.5、局部变量和成员变量
需求:定义计算器类 – 使用计算器完成加法运算 (基于2.4的代码即可)
代码演示 – 画图

局部变量和成员变量总结:
(1).位置不同:
局部变量定义在方法中(包括形式参数)
成员变量定义在类中,方法外。
(2).作用范围不同:
局部变量的作用范围是当前方法
成员变量的作用范围最小当前类
如果成员变量和局部变量同名,局部变量优先级别高(就近原则)
(3).初始值不同:
局部变量没有初始值
成员变量有初始值(由自身类型决定)
(4).在内存中位置不同:
局部变量在 栈内存
成员变量在 堆内存
(5).局部变量和成员变量同名,在方法中局部变量优先级别高。如何表示成员变量,通过对象名.变量名,或者 通过this关键字.

示例:
/**

  • 计算器类

  • 使用计算器完成加法运算

  • 1.复习类和对象

  • 2.方法的调用过程

  • public int add(int num1,int num2){} 方法的定义 方法的声明 num1,num2 形式参数 形参

  • int result = calc.add(num1,num2); 方法调用 num1,num2 实在参数 实参

  • 形参和实参要求个数相同,类型匹配,对应参数名称是否相同对结果没有任何影响

  • 方法调用的过程

    • 1.将实参赋给对应的形参
    • 2.执行方法
    • 3.返回方法的返回值
  • 3.局部变量和成员变量区别

  • 1.位置不同 局部变量定义在方法中(包括形式参数) 成员变量定义在类中

  • 2.作用范围不同 局部变量的作用范围是当前方法 成员变量的作用范围最小当前类

  •  如果成员变量和局部变量同名,局部变量优先级别高
    
  • 3.初始值不同:局部变量没有初始值 成员变量有初始值

  • 4.在内存中位置不同 局部变量在栈内存,成员变量在堆内存中
    */
    public class Calculator {
    String brand=“联想计算器”;
    double price;
    //int num1;
    public static void main(String[] args) {
    int num1;
    num1=20;
    int num2 = 30;
    //int result = num1+num2;//不仅知道干什么,还要知道怎么干
    Calculator calc = new Calculator();
    int result = calc.add(num1,num2);//只要知道干什么即可
    System.out.println(result);
    }

    public int add(int num1,int num2){
    int result;
    result = num1+num2;
    System.out.println(price);
    return result;
    }
    }
    内存图:

2.6、方法的重载
问题:上面的计算器只能计算两个整数的加法,如果是三个数相加呢?
解决:方法的重载

总结:
(1).定义: overload 方法名相同,参数不同
(2).判别方法重载的依据
1.在同一个类中 Calculator2
2.方法名相同 add
3.参数不同(个数不同,类型不同,顺序位置不同)
4.和 权限修饰符,返回值类型,参数名称 都无关
(3).好处: 更方便 更直观 更友好 更有针对性、屏蔽了使用差异
(4).常见的系统提供的重载方法:System.out.println();

两同三不同
同一个类,同一个方法名,
不同:参数列表不同(类型,个数,顺序不同)

示例:
/**

  • 计算器类

  • 使用计算器完成加法运算

  • 问题:计算两个整数的和没有问题,但是计算多个整数,或者计算double数的加法,不能很好的实现

  • 解决:方法的重载

  • 总结

  • 1.定义: overload 方法名相同,参数不同

  • 2.判别方法重载的依据
    1.在同一个类中 Calculator2
    2.方法名相同 add
    3.参数不同(个数不同,类型不同)
    4.和权限修饰符,返回值,参数名称无关
    3.好处
    你懂得 更方便 更直观 更友好
    4.方法重载我们已经见过了
    System.out.println();
    */
    public class Calculator2 {
    public static void main(String[] args) {
    int num1;
    num1=20;
    int num2 = 30;
    Calculator2 calc = new Calculator2();
    int result = calc.add(num1,num2);
    System.out.println(result);
    result = calc.add(10,20,30);
    System.out.println(result);
    //result = calc.add(10, calc.add(20, 30));//不方便
    double result2 = calc.add(3.14, 4.5);//不可以
    System.out.println(result2);
    System.out.println();
    }

    public int add(int num1,int num2){
    int result;
    result = num1+num2;
    return result;
    }

    public int add(int num1,int num2,int num3){
    return num1+num2+num3;
    }

    public double add(double num1,double num2){
    double result;
    result = num1+num2;
    return result;
    }

}
练习:设计一个计算器类,实现(两个数的)加减乘除功能
静态特征:计算器类型type、价格
动态行为:(两个数的)加减乘除方法
并提供测试类

2.7、构造方法
案例:定义计算机类 – Computer
代码演示Computer类的定义

构造方法总结:
(1).constructor 构造方法 构造器
(2).方法名和类名相同,不需要返回值类型
(3).作用:一般是做初始化操作,比如给成员变量赋值
(4).如何调用:通过new 类名()
(5).默认会提供一个无参数的构造方法
(6).public void Computer(){ } 不是构造方法,而是方法名和类名正好相同的普通成员方法
(7).如果某个类已经有一个或多个有参的构造方法那么就不会默认提供无参的构造方法,这个时候,如果有必要,你需要提供一个无参的构造方法(建议)

示例:
/**

  • 计算机类

  • 1.复习类定义和对象的创建

  • 2.构造方法

  • 1.constructor 构造方法 构造器

  • 2.方法名和类名相同,不需要返回值类型

  • 3.作用:一般是做初始化操作,比如给成员变量赋值

  • 4.如何调用 通过new

  • 5.默认会提供一个无参数的构造方法

    1. public void Computer(){} 不是构造方法,而是方法名和类名正好相同的普通成员方法
  • 3.构造方法的重载

  • 问题:创建对象后给多个属性赋值,需要多条语句来实现,繁琐

  • 解决:构造方法的重载

  • 局部变量和成员变量同名,在方法中局部变量优先级别高。如何表示成员变量,通过this关键字

  • 默认会提供一个无参数的构造方法,但是一旦提供了有参数的构造方法,无参数构造方法将不再提供。

  • 如果需要无参数构造方法,需要手动添加

  • 建议:每个类都要提供无参数的构造方法
    */
    public class Computer {
    //成员变量
    String cpu= “Intel”;//成员变量
    String mainBoard;
    String memory;
    String keyboard;
    String mouse;

    public Computer(){
    cpu = “AMD”;
    mainBoard =“技嘉”;
    System.out.println("------new Computer()-----");
    }

public Computer(String cpu,String mainBoard,String memory,String keyboard,String mouse){//形参 局部变量
this.cpu = cpu;
this.mainBoard = mainBoard;
this.memory = memory;
this.keyboard = keyboard;
this.mouse = mouse;
}
//public Computer(String cpu1,String mainBoard1,String memory1,String keyboard1,String mouse1){//形参 局部变量
// cpu = cpu1;
// mainBoard = mainBoard1;
// memory = memory1;
// keyboard = keyboard1;
// mouse = mouse1;
// }
//成员方法
public void start(){
System.out.println(“Starting…”);
}
public void close(){
System.out.println(“Closing…”);
}
public void showInfo(){
System.out.println(cpu+" “+mainBoard+” “+memory+” “+keyboard+” "+mouse);
}

public static void main(String[] args) {
	//生产一台电脑
	Computer c1 = new Computer();
	c1.cpu="Intel";
	c1.mainBoard="ASUS";
	c1.memory="samsung";
	c1.keyboard="罗技";
	c1.mouse="罗技";
	c1.start();
	c1.showInfo();
	c1.close();
	
	Computer c2 = new Computer("AMD","技嘉","金士顿","双飞燕键盘","双飞燕鼠标");//实参
	c2.start();
	c2.showInfo();
	c2.close();
}

}

2.8、构造方法的重载
问题:创建对象后给多个属性赋值,需要多条语句来实现,繁琐
解决:构造方法的重载

构造方法的重载类似方法的重载,符合普通方法重载的特性。
好处:初始化类

总结:
(1)局部变量和成员变量同名,在方法中局部变量优先级别高。如何表示成员变量,通过this关键字。
(2)默认会提供一个无参数的构造方法,但是一旦提供了有参数的构造方法,无参数构造方法将不再提供。
(3)如果需要无参数构造方法,需要手动添加。

  • 建议:每个类都要提供无参数的构造方法。

示例:
/**

  • 计算机类

  • 1.复习类定义和对象的创建

  • 2.构造方法

  • 1.constructor 构造方法 构造器

  • 2.方法名和类名相同,不需要返回值类型

  • 3.作用:一般是做初始化操作,比如给成员变量赋值

  • 4.如何调用 通过new

  • 5.默认会提供一个无参数的构造方法

    1. public void Computer(){} 不是构造方法,而是方法名和类名正好相同的普通成员方法
  • 3.构造方法的重载

  • 问题:创建对象后给多个属性赋值,需要多条语句来实现,繁琐

  • 解决:构造方法的重载

  • 局部变量和成员变量同名,在方法中局部变量优先级别高。如何表示成员变量,通过this关键字

  • 默认会提供一个无参数的构造方法,但是一旦提供了有参数的构造方法,无参数构造方法将不再提供。

  • 如果需要无参数构造方法,需要手动添加。

  • 建议:每个类都要提供无参数的构造方法
    */
    public class Computer {
    //成员变量
    String cpu= “Intel”;//成员变量
    String mainBoard;
    String memory;
    String keyboard;
    String mouse;

    public Computer(){
    cpu = “AMD”;
    mainBoard =“技嘉”;
    System.out.println("------new Computer()-----");
    }

public Computer(String cpu,String mainBoard,String memory,String keyboard,String mouse){//形参 局部变量
this.cpu = cpu;
this.mainBoard = mainBoard;
this.memory = memory;
this.keyboard = keyboard;
this.mouse = mouse;
}
// public Computer(String cpu1,String mainBoard1,String memory1,String keyboard1,String mouse1){//形参 局部变量
// cpu = cpu1;
// mainBoard = mainBoard1;
// memory = memory1;
// keyboard = keyboard1;
// mouse = mouse1;
// }
//成员方法
public void start(){
System.out.println(“Starting…”);
}
public void close(){
System.out.println(“Closing…”);
}
public void showInfo(){
System.out.println(cpu+" “+mainBoard+” “+memory+” “+keyboard+” "+mouse);
}

public static void main(String[] args) {
	//生产一台电脑
	Computer c1 = new Computer();
	c1.cpu="Intel";
	c1.mainBoard="ASUS";
	c1.memory="samsung";
	c1.keyboard="罗技";
	c1.mouse="罗技";
	c1.start();
	c1.showInfo();
	c1.close();
	
	Computer c2 = new Computer("AMD","技嘉","金士顿","双飞燕键盘","双飞燕鼠标");//实参
	c2.start();
	c2.showInfo();
	c2.close();
	
}

}

作业:
(1)复习今天所讲的知识点
(2)定义空间的一个坐标点,获取坐标信息(x,y,z),获取两个坐标点之间的距离
功能:定义空间的一个坐标点,获取坐标信息,获取两个坐标点之间的距离。
例子:Point.java

(3)技能:复习类和对象的所有内容

  • 1.类的定义
  • 2.成员变量
  • 3.成员方法
  • 4.构造方法
  • 5.局部变量和成员变量
  • 6.对象的创建和使用
  • 7.方法的重载
  • 8.对象的内存分配结构图

练习:
/**

  • 功能:定义空间的一个坐标点,获取坐标信息,获取两个坐标点之间的距离

  • 技能:复习类和对象的所有内容

  • 1.类的定义

  • 2.成员变量

  • 3.成员方法

  • 4.构造方法

  • 5.局部变量和成员变量

  • 6.对象的创建和使用

  • 7.方法的重载

  • 8.对象的内存分配结构图
    Math.sqrt((this.x-x)(this.x-x)+(this.y-y)(this.y-y)+(this.z-z)*(this.z-z));
    */
    public class Point {
    //成员变量
    int x;
    int y;
    int z;
    //构造方法
    public Point(){
    }
    public Point(int x,int y,int z){
    this.x = x;
    this.y = y;
    this.z = z;
    }

    //成员方法
    public void showInfo(){
    System.out.println(“x=”+x+",y="+y+",z="+z);
    }
    /**

    • 计算两个坐标点之间的距离
    • @param x
    • @param y
    • @param z
      /
      public double distance(int x,int y ,int z){
      //return Math.sqrt((this.x-x)
      (this.x-x)+(this.y-y)(this.y-y)+(this.z-z)(this.z-z));
      double temp = (this.x-x)(this.x-x)+(this.y-y)(this.y-y)+(this.z-z)*(this.z-z);
      double dis = Math.sqrt(temp);
      return dis;
      }

    public double distance(Point p){
    double temp = (this.x-p.x)(this.x-p.x)+(this.y-p.y)(this.y-p.y)+(this.z-p.z)*(this.z-p.z);
    double dis = Math.sqrt(temp);
    return dis;
    }

    public static void main(String[] args) {
    //point1
    Point p1 = new Point();
    p1.x = 20;
    p1.y = 50;
    p1.z = 20;
    p1.showInfo();
    //point2
    Point p2 = new Point(10, 30, 20);
    p2.showInfo();
    double dis =p2.distance(10, 30, 10);
    System.out.println(dis);
    double dis2 = p2.distance(p1.x, p1.y, p1.z);
    System.out.println(dis2);
    double dis3 = p2.distance(p1);
    System.out.println(dis3);
    }
    }

2.9、方法调用_基本类型参数
案例讲解技能点
功能:交换两个变量的值 –
技能:方法调用(参数是基本类型数据)

代码演示 – 画图说明
结论:方法调用中传递基本类型数据,不能在swap方法中改变main方法中变量的值

示例:
/**

  • 功能:交换两个变量的值

  • 技能:方法调用(参数是基本类型数据)

  • 结论:方法调用中传递基本类型数据,不能在swap方法中改变main方法中变量的值

  • @author enbo.xie
    */
    public class TestMethod1 {
    public static void main(String[] args) {
    //定义两个变量
    int num1 = 10;
    int num2 = 30;
    //输出交换前两个变量的值
    System.out.println(“main:交换前:num1=”+num1+",num2="+num2);
    //交换
    swap(num1,num2);//实参
    //输出交换后两个变量的值
    System.out.println(“main:交换后:num1=”+num1+",num2="+num2);
    }

    public static void swap(int num1,int num2){//形参
    System.out.println(“swap:交换前:num1=”+num1+",num2="+num2);
    int temp;
    temp = num1;
    num1 = num2;
    num2 = temp;
    System.out.println(“swap:交换后:num1=”+num1+",num2="+num2);
    }
    }
    内存结构图:

2.10、方法调用_引用类型参数
案例讲解技能点
功能:交换两个变量的值
技能:方法调用(参数是引用类型数据)
代码演示 – 画图说明

结论:
方法调用中传递引用类型数据,能在swap方法中改变main方法中变量的值。

栈:基本数据类型 局部变量
堆:引用类型变量的值 成员变量
方法区:static变量、字符串常量 – (暂时不讲)
基本数据类型:只在栈中可以直接分配内存的数据是基本数据类型。
引用数据类型:是数据的引用在栈中,但是他的对象在堆中。

示例:
/**

  • 功能:交换两个变量的值
  • 技能:方法调用(参数是引用类型数据)
  • 结论:方法调用中传递引用类型数据,能在swap方法中改变main方法中变量的值
  • @author enbo.xie
    */
    public class TestMethod2 {
    int num1;
    int num2;
    public static void main(String[] args) {
    //定义两个变量
    TestMethod2 tm2 = new TestMethod2();
    tm2.num1 = 10;
    tm2.num2 = 30;
    //输出交换前两个变量的值
    System.out.println(“main:交换前:num1=”+tm2.num1+",num2="+tm2.num2);
    //交换
    //swap(tm2.num1,tm2.num2);//实参
    swap(tm2);
    //输出交换后两个变量的值
    System.out.println(“main:交换后:num1=”+tm2.num1+",num2="+tm2.num2);
    }
    public static void swap(TestMethod2 tm2){//形参
    System.out.println(“swap:交换前:num1=”+tm2.num1+",num2="+tm2.num2);
    int temp;
    temp = tm2.num1;
    tm2.num1 = tm2.num2;
    tm2.num2 = temp;
    System.out.println(“swap:交换后:num1=”+tm2.num1+",num2="+tm2.num2);
    }
    // public static void swap(int num1,int num2){//形参
    // System.out.println(“swap:交换前:num1=”+num1+",num2="+num2);
    // int temp;
    // temp = num1;
    // num1 = num2;
    // num2 = temp;
    // System.out.println(“swap:交换后:num1=”+num1+",num2="+num2);
    // }
    }
    内存结构图:

2.11、在eclipse中进行程序调试 debug(A)
参考:debug.txt
提示:基于上面例子做演示即可。
程序的调试
1.debug de+bug 解决缺陷
2.作用:程序出错---->跟踪程序的执行过程---->观察变量的值的变化情况----->发现问题
3.操作
-1.添加断点breakpoint
-2.启动程序 debug as
-3.进行调试
F5 进入当前方法内
F6 执行下一条语句,一步一步执行,如果遇到方法,直接执行方法,不进入方法内(除非方法内部设置了断点)
F7 跳出当前方法
F8直接执行或跳到下一个断点
-4.发现问题
观察变量值的变化
-5.解决问题
-6.取消断点
可以单独取消
也可以全部取消 remove all breakpoints

2.12、this的作用和使用
案例讲解技能点 – 画图
示例:定义学生类 Student(name/ sex/ age/ score)

this总结:
1.为什么不能写stu1
* 1.先有类代码,再创建对象,开发写构造方法代码时,stu1还没有诞生呢
* 2.一个类可以创建多个对象,能写stu1,为什么不写stu2,stu3
* 这么一来,当局部变量和成员变量同名时候,如何解决同名的问题呢?
* 解决方案:Java提供了this关键字
2.this的作用:this是一个引用变量,指向当前对象自身。
每创建一个对象,就会创建一个this属性,指向当前对象自身

3.this的使用
1.this修饰 成员变量
this.name = name;
如果和局部变量同名,不能省略,如果不同名,可以省略.
在局部变量和成员变量同名的时候,我们使用this来引用成员变量。
2.this修饰 成员方法
this.introduce();
this可以省略。
3.this修饰 构造方法
this(name,sex,age);
必须是构造方法的第一条语句(暂时不解释,继承再讲)
4.注意:this不能出现在static方法中(暂时不解释)

示例:
/**

  • 学生类

  • 1.为什么不能写stu1

    • 1.先有类代码,再创建对象,开发写构造方法代码时,stu1还没有诞生呢
    • 2.一个类可以创建多个对象,能写stu1,为什么不写stu2,stu3
    • 这么一来,当局部变量和成员变量同名时候,如何解决同名的问题呢?
    • 解决方案:Java提供了this关键字
  • 2.this的作用:this是一个引用变量,指向当前对象自身。

  •  每创建一个对象,就会创建一个this属性,指向当前对象自身
    
  • 3.this的使用

  • 1.this修饰成员变量

  • this.name =name;

  • 如果和局部变量同名,不能省略,如果不同名,可以省略

  • 2.this修饰成员方法

  •  this.introduce();
    
  •   this可以省略
    
  • 3.this修饰构造方法

  •  this(name,sex,age);
    
  •   必须是构造方法的第一条语句
    
  • 4.注意

  • this不能出现在static方法中
    */
    public class Student2 {
    String name;//姓名
    String sex;//性别
    int age;//年龄
    double score;//分数

public Student2(String name,String sex,int age){		
	//System.out.println("--------------");
	this.name =name;
	this.sex = sex;
	this.age = age;
}
public Student2(String name,String sex,int age,double score){
	//new Student(name,sex,age);
	this(name,sex,age);
	this.score = score;
}

public void introduce(){		
	System.out.println(this.name +" "+this.sex+"  "+age+"  "+score);
}

public void shout(){
	System.out.println("站在高岗上大声的喊");
	//System.out.println(name +" "+sex+"  "+age+"  "+score);
	introduce();
	this.introduce();
	System.out.println("shout over");		
}

public static void main(String[] args) {
	Student2 stu1 = new Student2("小明","男",20,98);
	stu1.name="小明明";
	stu1.introduce();
	stu1.shout();
	Student2 stu2 = new Student2("小红","女",18,100);
	stu2.shout();
	stu2.introduce();		
}

}
内存图:

作业:
(1)理解基本数据类型参数和引用数据类型参数的内存分布图
(2)理解this的作用及内存分布图

(3)设计一个计算器:
1、具备两个数的加减乘除功能,并具备各种数据类型的加减乘除。
2、数据的输入通过键盘输入,比如 输入两个数字 然后输入 操作符 + - * /
然后自动计算结果 输出
3、不要三个数的操作:两个数的加减乘除 支持整数和小数

2.13、static的作用和内存分配
案例讲解技能点 – 画图(增加 方法区)
示例:学生类 Student ,增加学生所属学校
问题:如果1000个学生的学校是同一个学校,那个每创建一个学生对象,就会分配一个schoolName属性空间,内容相同,

  • 不好:浪费空间,如果修改,也要修改每个学生的schoolName,一共1000次
  • 解决方案:schoolName只有一份,节省空间,如果修改,只要修改一次
  • 使用static关键字

画图- 方法区(静态变量放在方法区里)第一次

方法区:静态变量、字符串常量
1.什么是static
static 静态的 类的
非static 非静态的 实例的 对象的
static String schoolName; 静态成员变量 static不能修饰局部变量
double score; 实例变量 非静态变量
static变量只有一份

2.static内存结构图 (画图)

  • static变量只有一份,存在 方法区 中
    示例:
    /**
  • 学生类
  • 问题:如果1000个学生的学校是同一个学校,那个每创建一个学生对象,就会分配一个schoolName属性空间,内容相同,
  • 不好:浪费空间,如果修改,也要修改每个学生的schoolName,一共1000次
  • 解决方案:schoolName只有一份,节省空间,如果修改,只要修改一次
  • 使用static关键字
  • 1.什么是static
  • static 静态的
  • 非static 非静态的 实例的
  • static String schoolName;静态变量
    double score; 实例变量 非静态变量
  • static变量只有一份
  • 2.static 内存结构图
  • static变量只有一份,存在方法区中
  • 3.static变量和非static变量的区别
  • 1.在内存中份数不同
  • 不管有多少个对象,static变量只有1份。对于每个对象,实例变量都会有单独的一份
  •  static变量是属于整个类的,也称为类变量
    
  •  而非静态变量是属于对象的,也称为实例变量
    
  • 2.在内存中存放的位置不同
  •  静态变量存在方法区中
    
  •  实例变量存在堆内存中 *  
    
  • 3.访问的方式不同
  •  实例变量: 对象名.变量名  stu1.name="小明明";
    
  •  静态变量:对象名.变量名  stu1.schoolName="西二旗小学"; 不推荐如此使用
    
  •  	   类名.变量名  Student.schoolName="东三旗小学"; 推荐使用
    
  • 4.在内存中分配空间的时间不同
  •  实例变量:创建对象的时候才分配了空间   new Student
    
  •  静态变量:第一次使用类的时候 
    
  •  		Student.schoolName="东三旗小学";
    
  •  		或者Student stu1 = new Student("小明","男",20,98);
    

*/
public class Student {
String name;//姓名
String sex;//性别
int age;//年龄
static String schoolName;
double score;//分数

public Student(String name,String sex,int age){		
	//System.out.println("--------------");
	this.name =name;
	this.sex = sex;
	this.age = age;
}
public Student(String name,String sex,int age,double score){
	//new Student(name,sex,age);
	this(name,sex,age);
	this.score = score;
}
public Student(String name,String sex,int age,double score,String schoolName){
	//new Student(name,sex,age);
	this(name,sex,age);
	this.score = score;
	this.schoolName = schoolName;
}

public void introduce(){		
	System.out.println(this.name +" "+this.sex+"  "+age+"  "+score+"  "+schoolName);
}

public void shout(){
	System.out.println("站在高岗上大声的喊");
	//System.out.println(name +" "+sex+"  "+age+"  "+score);
	introduce();
	this.introduce();
	System.out.println("shout over");		
}

public static void main(String[] args) {
	//Student.schoolName="东三旗小学";
	Student stu1 = new Student("小明","男",20,98);
	stu1.name="小明明";
	stu1.schoolName="西二旗小学";
	
	Student stu2 = new Student("小红","女",18,100);
	
	stu1.introduce();
	stu1.shout();
	
	stu2.shout();
	stu2.introduce();		
}

}
内存图:

2.14、static变量和非static变量的区别
Tips:结合上面的代码和图讲解
3.static变量和非static变量的区别 (都是成员变量,不是局部变量)

  • (1).在内存中份数不同

  • 不管有多少个对象,static变量只有1份。对于每个对象,实例变量都会有单独的一份

  • static成员变量是属于整个类的,也称为 类变量

  • 而非静态成员变量是属于 对象的,也称为 实例变量

  • (2).在内存中存放的位置不同

  •  静态变量存在  方法区  中
    
  •  实例变量存在  堆内存  中 *  
    
  • (3).访问的方式不同

  •  实例变量: 对象名.变量名  stu1.name="小明明";
    
  •  静态变量:对象名.变量名  stu1.school="西二旗小学"; 不推荐如此使用
    
  •  	         类名.变量名  Student.school="东三旗小学"; 推荐使用
    
  • (4).在内存中分配空间的 时间不同

  •  实例变量:创建对象的时候才分配了空间  new 
    
  •  静态变量:第一次使用类的时候   方法区
    
  •  Student.schoolName="东三旗小学";
    
  •  或者Student stu1 = new Student("小明","男",20,98);
    

2.15、static方法
(1).作用:用来操作 静态变量
(2).访问方式
Student.showSchoolInfo();//当前类中可以省略类名
stu1.showSchoolName();//不推荐使用
(3).不可以
静态方法中 不可以 直接访问 实例变量:System.out.println(“name=”+name);
静态方法中 不可以 访问 this,super:System.out.println(this);
静态方法中 不可以 直接访问 实例方法 :introduce();
why?
静态变量,静态方法在第一次访问类的时候在内存分配空间
但是 实例变量,实例方法,this,super是在创建每个对象的时候才在内存分配空间
所以静态方法中不能直接访问 实例变量,实例方法,this,super,
因为此时可能对象还没有创建呢,这些内容在内存中还不存在!
(4).可以
实例方法中可以直接访问 静态变量,静态方法
原因同上

以上的区别都是因为 静态的事物 与 实例的产生 在时间上是有先后顺序的关系!

示例:
/**

  • 学生类

  • 问题:如果1000个学生的学校是同一个学校,那个每创建一个学生对象,就会分配一个schoolName属性空间,内容相同,

  • 不好:浪费空间,如果修改,也要修改每个学生的schoolName,一共1000次

  • 解决方案:schoolName只有一份,节省空间,如果修改,只要修改一次

  • 使用static关键字

  • 1.static变量

  • 2.static方法

  • 1.作用:用来操作静态变量

  • 2.访问方式

  •  Student.showSchoolName();//当前类中可以省略类名
    
  •  stu1.showSchoolName();//不推荐使用
    
  • 3.不可以

  •  静态方法中不可以直接访问实例变量:System.out.println("name="+name);
     静态方法中不可以访问this,super:System.out.println(this);
     静态方法中不可以直接访问实例方法 :introduce();
     
     why????
     静态变量,静态方法在第一次访问类的时候在内存分配空间
     但是实例变量,实例方法,this,super是在创建每个对象的时候才在内存分配空间
     所以静态方法中不能直接访问实例变量,实例方法,this,super,
     因为此时可能对象还没有创建呢,这么内容在内存中还不存在呢
    
  • 4.可以

  •  实例方法中可以直接访问静态变量,静态方法
    
  •  原因同上
    

*/
public class Student4 {
String name;//姓名
String sex;//性别
int age;//年龄
static String schoolName;
double score;//分数

public Student4(String name,String sex,int age){		
	//System.out.println("--------------");
	this.name =name;
	this.sex = sex;
	this.age = age;
}
public Student4(String name,String sex,int age,double score){
	//new Student(name,sex,age);
	this(name,sex,age);
	this.score = score;
}
public Student4(String name,String sex,int age,double score,String schoolName){
	//new Student(name,sex,age);
	this(name,sex,age);
	this.score = score;
	this.schoolName = schoolName;
}

public static void showSchoolName(){
	System.out.println("schoolName="+schoolName);
	//System.out.println("name="+name);
	//System.out.println(this);
	//introduce();
}

public void introduce(){
	//static int age=12;
	System.out.println(this.name +" "+this.sex+"  "+age+"  "+score+"  "+schoolName);
	showSchoolName();
	System.out.println(this);
}

public void shout(){
	System.out.println("站在高岗上大声的喊");
	//System.out.println(name +" "+sex+"  "+age+"  "+score);
	introduce();
	this.introduce();
	System.out.println("shout over");		
}

public static void main(String[] args) {
	Student4.showSchoolName();
	Student4.schoolName="东三旗小学";
	Student4.showSchoolName();
	String name = "小明";
	Student4 stu1 = new Student4(name,"男",20,98);
	stu1.name="小明明";
	stu1.schoolName="西二旗小学";
	stu1.showSchoolName();
	Student4 stu2 = new Student4("小红","女",18,100);
	
	stu1.introduce();
	stu1.shout();
	
	stu2.shout();
	stu2.introduce();		
}

}

2.16、static代码块/代码块
代码演示说明

总结:
static代码块

  • 1.语法 static{ }
  • 2.执行时间,执行次数:第一次加载该类的时候执行,并且只执行1次
  • 3.作用:加载类时给静态变量初始化
  • 4.static代码块可以有多个,从前向后依次执行,只执行1次

代码块 (了解即可)
*1.语法 { }
*2.执行时间,执行次数: 创建每个对象之前执行。每创建一个对象都会执行一次
*3.代码块可以有多个,从前向后依次执行
*4.作用:没有多大的作用,使用不多;可以将多个构造方法中的共同代码提取出来,放入代码块

注意:搞清楚 静态 和 非静态的 执行时间及顺序。

类的成员(类的儿子)

  • 1.成员变量(static静态变量(类变量) 和 实例变量(属于对象的变量))
  • 2.成员方法(static静态方法 和 实例方法)
  • 3.构造方法 (构造方法的重载)
  • 4.静态代码块
  • 5.代码块
  • 6.内部类

示例:
/**

  • 学生类

  • 问题:如果1000个学生的学校是同一个学校,那个每创建一个学生对象,就会分配一个schoolName属性空间,内容相同,

  •  不好:浪费空间,如果修改,也要修改每个学生的schoolName,一共1000次
    
  • 解决方案:schoolName只有一份,节省空间,如果修改,只要修改一次

  •   使用static关键字
    
  • 1.static变量

  • 2.static方法

  • 3.static静态代码块

  •  1.语法  static{  }
    
  •  2.执行时间,执行次数:第一加载该类的时候执行,并且只执行1次
    
  •  3.作用:加载类时给静态变量初始化
    
  •  4.static代码块可以有多个,从前向后依次执行
    
  • 4.代码块 了解即可

  •  1.语法{}
    
  •  2.执行时间,执行次数: 创建每个对象之前执行。每创建一个对象都会执行一次
    
  •  3.代码块可以有多个,从前向后依次执行
    
  •  4.作用:没有多大的作用,使用不多;可以将多个构造方法中的共同代码提取出来,放入代码块
    
  • 5.类的成员(类的儿子)

    • 1.成员变量(静态变量和实例变量)
    • 2.成员方法(静态方法和实例方法)
    • 3.构造方法
    • 4.静态代码块
    • 5.代码块
    • 6.内部类
      */
      public class Student {
      String name;//姓名
      static String schoolName;
      static{
      schoolName=“西二旗小学”;
      //name=“小明”;
      System.out.println("-------static code block---------");
      }
      public Student(){
      System.out.println("------Student()---------");
      }
      public static void showSchoolName(){
      System.out.println(“schoolName=”+schoolName);
      }

    public void introduce(){
    System.out.println(this.name +" "+schoolName);
    showSchoolName();
    System.out.println(this);
    }
    static{
    System.out.println(“bbbbb”);
    }
    public void shout(){
    System.out.println(“站在高岗上大声的喊”);
    introduce();
    this.introduce();
    System.out.println(“shout over”);
    }

    public static void main(String[] args) {
    Student.showSchoolName();
    Student stu1 = new Student();
    Student stu2 = new Student();
    Student stu3 = new Student();
    }
    static{
    System.out.println(“ccccc”);
    }
    }

2.17、package和import的引入和使用
1、package包
(1).为什么要定义包
举例:文件夹 子文件夹 省 县 乡
类太多了
1).同一个包下不能有同名的类
2).方便管理
3) .如果一个类没有定义包,那么其他类就不能引用它

(2).如何定义包

  • com.csqf.oop.object
  • com.bjsxt.oop.object2
  • com.bjsxt.sxtoa.dao
  • com.bjsxt.sxtoa.dao.impl
  • 域名.机构名.项目名.模块.子模块
  • 全部小写,全部使用英文

(3).如何使用包

  • package com.bjsxt.oop.object2; //
  • 分号不可少
  • 必须是第一条语句

(4).其他:jdk的常用包

  • java.util 工具包
  • java.awt 图形界面编程
  • java.io 输入输出流
  • java.nio 新输入输出流
  • java.lang 语言包 String System
  • java.net socket编程 网络通信
  • java.sql JDBC包 访问数据库

2、import导入引入
(1).为什么需要import

  • 同一个包下的类不需要导入import
  • 不同包的类需要导入,如果不导入,就需要完整路径,简便起见,import即可//快捷键:ctrl+shift+O
    如果一个类是默认包,则其他类无法引入。

(2).如何import
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import com.bjsxt.oop.object.Calculator;
import java.util.;//可以使用一次导入多个类
import com.bjsxt.*;//只包括当前包,不包括子包和后代包

(3).注意事项

  • 1.默认当前包 Student stu;
  • 2.java.lang包下的类不需要导入String str;
  • 3.Java项目开发时一定要定义包,否则其他包无法import
  • 4.如果一个类中使用到了不同包的中同名类,怎么办?? 比如:Date
    可以import一个类,另外一个类需要完整路径
  • 5.静态导入 static import
    import static java.lang.Math.; 以静态属性和静态方法结尾
    import java.lang.Math.
    ; 以类结尾
    示例:
    import java.sql.Date;
    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    import com.bjsxt.oop.object.Calculator;
    import static java.lang.Math.*;
    /**
  • 1.package包
    • 1.为什么要定义包
    •  举例:文件夹 子文件夹   省 县  乡
      
    • 类太多了
    • 1.同一包下不能有同名的类
    • 2.方便管理
    • 2.如何定义包
      • com.bjsxt.oop.object
      • com.bjsxt.oop.object2
      • com.bjsxt.sxtoa.dao
      • com.bjsxt.sxtoa.dao.impl
      • 域名.机构名.项目名.模块.子模块
      • 全部小写,全部使用英文 *
    • 3.如何使用包
    • package com.bjsxt.oop.object2;//
    • 分号不可少
    • 必须是第一条语句
    • 4.其他:jdk的常用包
    • java.util 工具包
    • java.awt 图形界面编程
    • java.io 输入输出流
    • java.nio 新输入输出流
    • java.lang 语言包 String System
    • java.net socket编程 网络通信
    • java.sql JDBC包 访问数据库
  • 2.import导入引入
    • 1.为什么需要import

    • 同一个包的下类不需要导入import

    • 不同包的类需要导入,如果不导入,就需要完整路径,简便起见,import即可

    • 2.如何import

    • import java.util.ArrayList;
      import java.util.HashSet;
      import java.util.List;
      import com.bjsxt.oop.object.Calculator;
      import java.util.;//可以使用一次导入多个类
      import com.bjsxt.*;//只包括当前包,不包括子包和后代包

    • 3.注意事项

    • 1.默认当前包 Student stu;

    • 2.java.lang包下的类不需要导入String str;

    • 3.Java项目开发时一定要定义包,否则其他包无法import

    • 4.如果一个类中使用到了不同包的中同名类,怎么办??可以import一个类,另外一个类需要完整路径

    • 5.静态导入static import

    • import static java.lang.Math.*; 以静态属性和静态方法结尾

    • import java.lang.Math.*; 以类结尾
      */
      public class TestPackageImport {
      public static void main(String[] args) {
      java.util.Scanner input = new java.util.Scanner(System.in);
      List list = new ArrayList();
      Set set = new HashSet();
      Calculator calc = new Calculator();
      Student stu;
      String str;
      //Teacher teacher;
      java.util.Date date =new java.util.Date();//util
      Date date2 = Date.valueOf(“1999-12-23”);//sql
      // System.out.println(Math.PI);
      // System.out.println(Math.E);
      // System.out.println(Math.abs(-234));
      // System.out.println(Math.sqrt(49));
      System.out.println(PI);
      System.out.println(E);
      System.out.println(abs(-234));
      System.out.println(sqrt(49));
      }
      }

作业:
(1)充分理解static变量、String类型,并搞清楚他们的内存结构图
(2)编程题目:从键盘任意输入一串字符(必须包含大小写、数字),输出字符串和它的长度,然后对字符串进行分析提取,把大写、小写、数字分别提取出来,并输出各部分的长度。
(3)学会查看API文档

2.18、引入继承

参考:JAVA面向对象编程_enbo.pptx
Tips:概念介绍,直接代码演示上面是继承。

示例:Animal.java
/**

  • 继承inheritance

  • 1.什么是继承

  • 父类 超类

  • 子类 派生类

  • 子类可以从父类继承某些属性和方法

  • 2.继承的好处

  • 重用代码,避免重复

  • 3.其他

  • 如果一个类没有显式extends任何类,默认的继承Object类

  • Object类所有类的祖先,任何一个类都直接或者间接的继承了Object

  • Object的方法是所有类都具有的
    */
    public class Animal extends Object{
    //field 属性
    String color;
    int age;

    //method方法
    public void eat(){
    System.out.println("-------Animal eating -------- “);
    }
    public void sleep(){
    System.out.println(”-------Animal sleeping-------- “);
    }
    public void introduce(){
    System.out.println(“Animal:color=”+color+”,age="+age);
    }
    }
    public class Dog extends Animal{
    //特殊的属性
    String nickName;//昵称
    String strain;//种类 sort type’

    //特有的方法
    public void guard(){
    System.out.println(“dog是人类安全的守护神”);
    }
    }
    public class TestAnimal {
    public static void main(String[] args) {
    // Animal an = new Animal();
    // an.age=2;
    // an.color=“yellow”;
    // an.eat();
    // an.sleep();
    // an.introduce();
    Dog dog = new Dog();
    dog.age=3;//从父类继承的属性
    dog.color=“black and blue”;//从父类继承的属性
    dog.nickName=“旺财”;//dog自己的属性
    dog.strain=“拉布拉多犬”;//dog自己的属性
    dog.eat();//从父类继承的属性
    dog.sleep();//从父类继承的属性
    dog.introduce();//从父类继承的属性
    dog.guard();//dog自己的方法
    }
    }

总结:
继承inheritance
1.什么是继承 – extends
*父类 超类
*子类 派生类
*子类可以从父类继承 某些 属性和方法

2.继承的好处
*重用代码,避免重复

3.其他
*如果一个类没有显式 extends 任何类,默认的继承 Object类
*Object类所有类的祖先,任何一个类都直接或者间接的继承了Object
*Object的某些方法是所有类都具有的!

2.19、方法的重写
问题:经上面示例发现,子类dog继承父类,发现父类的某些方法已经不满足子类的要求了。
解决:方法的重写
示例:
/*父类:动物类 /
public class Animal extends Object{
//field 属性
String color;
int age;
//method方法
public void eat(){
System.out.println("-------Animal eating -------- “);
}
public void sleep(){
System.out.println(”-------Animal sleeping-------- “);
}
public void introduce(){
System.out.println(“Animal:color=”+color+”,age="+age);
}
public String toString() {
return “Animal:color=”+color+",age="+age;
}
}
/子类:Dog类/
public class Dog extends Animal{
//特殊的属性
String nickName;//昵称
String strain;//种类 sort type’
//特有的方法
public void guard(){
System.out.println(“dog是人类安全的守护神”);
}
public void introduce(){
//方式二
//继承父类的introudce
super.introduce();
//增加自己的introduce内容
System.out.println(“Dog:nickName=”+nickName+",age="+age);
//方式一
//System.out.println(“Animal:color=”+color+",age="+age);
//System.out.println(“Dog:color=”+color+",age="+age+",nickName="+nickName+",strain="+strain);
}
public String toString() {
return “Dog:color=”+color+",age="+age+",nickName="+nickName+",strain="+strain;
}
}
/

  • 缺点:Animal:color=black and blue,age=3

  • Dog类做自我介绍是没有介绍自己特有的属性,因为introduce方法是从父类继承的,但是已经无法满足子类的要求

  • 解决:方法的重写

  • 总结:重写

  • 1.方法的重写,方法的覆盖 override

  • 2.使用场合:父类的方法不能满足子类要求时,子类重写父类的方法

  • 3.语法要求:方法名,参数必须相同,

  • 权限修饰符 返回值类型 抛出的异常类型,相同没有问题,也可以不同,这个不同是有要求,不是随意不同(以后在表)

  • public void introduce() throws Exception{}

  • 问题:

  •  System.out.println(an);
     System.out.println(an.toString());
     println()作用:多个重载的方法,参数可以是基本数据类型,也可以是引用数据类型
     但是都会将这些类型转换成字符串输出
     如果是对象,会自动的调用toString(),转换成字符串并输出
    

    问题:为什么com.bjsxt.oop.inheritance2.Animal@11a40fff
    com.bjsxt.oop.inheritance2.Dog@55e6cb2a
    原因:继承了Object的toString(),但是已经不能满足需要了,此时可以重写

  • 总结:Object类

  • 1.地位:继承树的顶级类

    • 如果一个类没有显式extends任何类,默认的继承Object类
    • Object类所有类的祖先,任何一个类都直接或者间接的继承了Object
    • Object的方法是所有类都具有的
  • 2.常用方法

  •    obj.getClass();得到类的结构信息  反射
     obj.toString();//将对象格式化字符串
     obj.equals(obj)//判断两个对象内容是否相同
     obj.hashCode():哈希码  集合类 容器类
     
     obj.notify(); 多线程
     obj.notifyAll();多线程
     obj.wait(timeout);多线程
      finalize() //垃圾回收
      Object clone()	//克隆 原型设计模式 快速复制
    

*/
public class TestAnimal {
public static void main(String[] args) {
Animal an = new Animal();
an.age=2;
an.color=“yellow”;
an.eat();
an.sleep();
an.introduce();
System.out.println(an);
System.out.println(an.toString());
System.out.println(123);

	Dog  dog = new Dog();
	dog.age=3;//从父类继承的属性
	dog.color="black and blue";//从父类继承的属性
	dog.nickName="旺财";//dog自己的属性
	dog.strain="拉布拉多犬";//dog自己的属性
	dog.eat();//从父类继承的属性
	dog.sleep();//从父类继承的属性
	dog.introduce();//从父类继承的属性
	dog.guard();//dog自己的方法
	System.out.println(dog);
	System.out.println(dog.toString());
	
	Object  obj = new Object();
}

}

总结:方法的重写

  • 1.方法的重写,方法的覆盖 override
  • 2.使用场合:父类的方法不能满足子类要求时,子类重写父类的方法
  • 3.语法要求:方法名,参数 必须相同,
  • 权限修饰符 返回值类型 抛出的异常类型,相同没有问题,也可以不同,这个不同是有要求,不是随意不同(以后再讲)
  • public void introduce() throws Exception{}

问题1:
System.out.println(an);
System.out.println(an.toString());
println()作用:多个重载的方法,参数可以是基本数据类型,也可以是引用数据类型
但是都会将这些类型转换成字符串输出
如果是对象,会自动的调用toString(),转换成字符串并输出。

问题2:为什么结果是
com.bjsxt.oop.inheritance2.Animal@11a40fff
com.bjsxt.oop.inheritance2.Dog@55e6cb2a
原因:继承了Object的toString(),但是已经不能满足需要了,此时可以重写!

2.20、方法的重写和Object类总结
示例:
/**
*父类:动物类
*/
public class Animal extends Object{
//field 属性
String color;
int age;

//method方法
public void eat(){
	System.out.println("-------Animal eating -------- ");
}
public void sleep(){
	System.out.println("-------Animal sleeping-------- ");
}
public void introduce(){
	System.out.println("Animal:color="+color+",age="+age);
}

public String toString() {
        return "Animal:color="+color+",age="+age;
}

}
/**

  • 子类:Dog类
    */
    public class Dog extends Animal{
    //特殊的属性
    String nickName;//昵称
    String strain;//种类 sort type’

    //特有的方法
    public void guard(){
    System.out.println(“dog是人类安全的守护神”);
    }
    public void introduce(){
    //继承父类的introudce
    super.introduce();
    //增加自己的introduce内容
    System.out.println(“Dog:nickName=”+nickName+",age="+age);
    //System.out.println(“Animal:color=”+color+",age="+age);
    //System.out.println(“Dog:color=”+color+",age="+age+",nickName="+nickName+",strain="+strain);
    }
    public String toString() {
    return “Dog:color=”+color+",age="+age+",nickName="+nickName+",strain="+strain;
    }
    }
    /**

  • 缺点:Animal:color=black and blue,age=3

  •  Dog类做自我介绍是没有介绍自己特有的属性,因为introduce方法是从父类继承的,
    
  •  但是已经无法满足子类的要求
    
  • 解决:方法的重写

  • 总结:重写

  • 1.方法的重写,方法的覆盖 override

  • 2.使用场合:父类的方法不能满足子类要求时,子类重写父类的方法

  • 3.语法要求:方法名,参数必须相同,

  • 权限修饰符 返回值类型 抛出的异常类型,相同没有问题,也可以不同,这个不同是有要求,不是随意不同(以后在表)

  • public void introduce() throws Exception{}

  • 问题:

  •  System.out.println(an);
     System.out.println(an.toString());
     println()作用:多个重载的方法,参数可以是基本数据类型,也可以是引用数据类型
     但是都会将这些类型转换成字符串输出
     如何是对象,会自动的调用toString(),转换成字符串并输出
    

    问题:为什么com.bjsxt.oop.inheritance2.Animal@11a40fff
    com.bjsxt.oop.inheritance2.Dog@55e6cb2a
    原因:继承了Object的toString(),但是已经不能满足需要了,此时可以重写

  • 总结:Object类

  • 1.地位:继承树的顶级类

    • 如果一个类没有显式extends任何类,默认的继承Object类
    • Object类所有类的祖先,任何一个类都直接或者间接的继承了Object
    • Object的方法是所有类都具有的
  • 2.常用方法

  • obj.getClass();得到类的结构信息 反射
    obj.toString();//将对象格式化字符串
    obj.equals(obj)//判断两个对象内容是否相同
    obj.hashCode():哈希码 集合类 容器类

    obj.notify(); 多线程
    obj.notifyAll();多线程
    obj.wait(timeout);多线程
     finalize() //垃圾回收
     Object clone()	//克隆 原型设计模式 快速复制
    

*/
public class TestAnimal {
public static void main(String[] args) {
Animal an = new Animal();
an.age=2;
an.color=“yellow”;
an.eat();
an.sleep();
an.introduce();
System.out.println(an);
System.out.println(an.toString());
System.out.println(123);

	Dog  dog = new Dog();
	dog.age=3;//从父类继承的属性
	dog.color="black and blue";//从父类继承的属性
	dog.nickName="旺财";//dog自己的属性
	dog.strain="拉布拉多犬";//dog自己的属性
	dog.eat();//从父类继承的属性
	dog.sleep();//从父类继承的属性
	dog.introduce();//从父类继承的属性
	dog.guard();//dog自己的方法
	System.out.println(dog);
	System.out.println(dog.toString());
	
	Object  obj = new Object();
}

}

总结:Object类介绍
1.地位:继承树的顶级类

  • 如果一个类没有显式extends任何类,默认的继承Object类
  • Object类所有类的祖先,任何一个类都直接或者间接的继承了Object
  • Object的public方法是所有类都具有的
    2.常用方法
    obj.getClass();得到类的结构信息 反射
    obj.toString();//将对象格式化字符串
    obj.equals(obj)//判断两个对象内容是否相同
    obj.hashCode():哈希码 集合类 容器类
    obj.notify(); 多线程
    obj.notifyAll();多线程
    obj.wait(timeout);多线程
    finalize() //垃圾回收
    Object clone() //克隆 原型设计模式 快速复制

2.21、子类对象的内存结构图
示例:
/**
*父类:动物类

  • @author enbo.xie
    */
    public class Animal extends Object{
    //field 属性
    String color;
    int age;
    public Animal(){
    super();
    }
    public Animal(String color,int age){
    super();
    this.color = color;
    this.age = age;
    }
    //method方法
    public void eat(){
    System.out.println("-------Animal eating -------- “);
    }
    public void sleep(){
    System.out.println(”-------Animal sleeping-------- “);
    }
    public void introduce(){
    System.out.println(“Animal:color=”+color+”,age="+age);
    }

    public String toString() {
    return “Animal:color=”+color+",age="+age;
    }
    }
    /**

  • 子类:Dog类

  • @author enbo.xie
    */
    public class Dog extends Animal{
    //特殊的属性
    String nickName;//昵称
    String strain;//种类 sort type’

    public Dog(){
    super();//默认调用父类无参数的构造方法
    }
    public Dog(String color,int age,String nickName,String strain){
    //super();
    //this.color = color;
    //this.age = age;
    super(color,age);//不再调用无参数的构造方法,而是显式调用有参数构造方法
    //super();
    //this();
    this.nickName = nickName;
    this.strain = strain;
    }
    //特有的方法
    public void guard(){
    System.out.println(“dog是人类安全的守护神”);
    }
    public void introduce(){
    //继承父类的introudce
    super.introduce();
    //增加自己的introduce内容
    System.out.println(“Dog:nickName=”+nickName+",age="+age);
    //System.out.println(“Animal:color=”+color+",age="+age);
    //System.out.println(“Dog:color=”+color+",age="+age+",nickName="+nickName+",strain="+strain);
    }
    public String toString() {
    return “Dog:color=”+super.color+",age="+super.age+",nickName="+this.nickName+",strain="+this.strain;
    }
    }
    /**
    *1. 创建子类对象时内存分配图

  • Dog dog = new Dog();

  • 即将创建一个Dog子类对象,会自上而下分别创建Object,Animal,和Dog三个对象

  • 每个对象除了具有自身的成员变量外,都还有分配this和super两个属性空间

  • this指向当前对象自身

  • super指向当前对象的直接父类对象

  • Object,Animal,和Dog三个对象是依靠super关键字联系起来

  • 最终将Dog子类的内存起始地址赋给dog引用变量

  • 注意:分配内存时父类对象Animal的color,age属性并没有在Dog对象中分配空间

  • 2.继承条件下对象的创建过程(代码分析)

  • 第一语句默认是super(),代表父类的无参数构造方法

  • 也可以显式指定父类的其他构造方法 super(color,age)

  • 也可以显式的指定当前对象的其他构造方法 this()

  • 3.super关键字的用法

  • 1.作用:执行当前对象的父类对象,每个对象都有一个super属性,创建对象 时分配空间

  • 2.使用

  •  1.修饰父类的成员变量  super.color
    
  •  2.修饰父类的成员方法  super.introduce(); 不要求是第一条语句
    
  •  3.修饰父类的构造方法  super(color,age);   必须是第一条语句
    
  • 3.注意

  •  this和super不能同时出现在子类的构造方法中
    
  • 1.this和super都必须是构造方法的第一条语句,如果都存在,谁是第二条语句多错误

  •  2.更核心的原因:继承条件下对象的创建过程
    
  • @author enbo.xie
    */
    public class TestAnimal {
    public static void main(String[] args) {
    Dog dog = new Dog();
    dog.age=3;//从父类继承的属性
    dog.color=“black and blue”;//从父类继承的属性
    dog.nickName=“旺财”;//dog自己的属性
    dog.strain=“拉布拉多犬”;//dog自己的属性
    dog.introduce();

     Dog dog2 = new Dog("黑色", 3, "小强", "雪纳瑞");
     dog2.introduce();
    

// dog.eat();//从父类继承的属性
// dog.sleep();//从父类继承的属性
// dog.introduce();//从父类继承的属性
// dog.guard();//dog自己的方法
}
}
子类对象创建的内存结构图:

总结:
子类对象创建的过程总结:
(1).创建子类对象时内存分配图
Dog extends Animal
Dog dog = new Dog();
创建一个Dog子类对象,会自上而下分别创建Object,Animal,和Dog三个对象
每个对象除了具有自身的 成员变量 外,都还要分配this和super两个属性空间
this指向当前对象自身
super指向当前对象的 直接父类对象
Object,Animal,和Dog三个对象是依靠super关键字联系起来
最终将Dog子类的内存起始地址赋给dog引用变量

注意:分配内存时父类对象Animal的color,age属性并没有在Dog对象中分配空间
(2).继承条件下对象的创建过程(代码分析)
new Dog()
第一语句默认是super(),代表父类的无参数构造方法
也可以显式指定父类的其他构造方法 super(color,age)
也可以显式的指定当前对象的其他构造方法 this()

2.22、super关键字的作用和使用

示例:(代码调试演示)
/**父类:动物类 /
public class Animal extends Object{
//field 属性
String color;
int age;
public Animal(){
super();
}
public Animal(String color,int age){
super();
this.color = color;
this.age = age;
}
//method方法
public void eat(){
System.out.println("-------Animal eating -------- “);
}
public void sleep(){
System.out.println(”-------Animal sleeping-------- “);
}
public void introduce(){
System.out.println(“Animal:color=”+color+”,age="+age);
}
public String toString() {
return “Animal:color=”+color+",age="+age;
}
}
/子类:Dog类/
public class Dog extends Animal{
//特殊的属性
String nickName;//昵称
String strain;//种类 sort type’
public Dog(){
super();//默认调用父类无参数的构造方法
}
public Dog(String color,int age,String nickName,String strain){
//super();
//this.color = color;
//this.age = age;
super(color,age);//不再调用无参数的构造方法,而是显式调用有参数构造方法
//super();
//this();
this.nickName = nickName;
this.strain = strain;
}
//特有的方法
public void guard(){
System.out.println(“dog是人类安全的守护神”);
}
public void introduce(){
//继承父类的introudce
super.introduce();
//增加自己的introduce内容
System.out.println(“Dog:nickName=”+nickName+",age="+age);
//System.out.println(“Animal:color=”+color+",age="+age);
//System.out.println(“Dog:color=”+color+",age="+age+",nickName="+nickName+",strain="+strain);
}
public String toString() {
return “Dog:color=”+super.color+",age="+super.age+",nickName="+this.nickName+",strain="+this.strain;
}
}
/

*1. 创建子类对象时内存分配图

  • Dog dog = new Dog();

  • 创建一个Dog子类对象,会自上而下分别创建Object,Animal,和Dog三个对象

  • 每个对象除了具有自身的成员变量外,都还有分配this和super两个属性空间

  • this指向当前对象自身

  • super指向当前对象的直接父类对象

  • Object,Animal,和Dog三个对象是依靠super关键字联系起来

  • 最终将Dog子类的内存起始地址赋给dog引用变量

  • 注意:分配内存时父类对象Animal的color,age属性并没有在Dog对象中分配空间

  • 2.继承条件下对象的创建过程(代码分析)

  • 第一语句默认是super(),代表父类的无参数构造方法

  • 也可以显式指定父类的其他构造方法 super(color,age)

  • 也可以显式的指定当前对象的其他构造方法 this()

  • 3.super关键字的用法

  • 1.作用:执行当前对象的父类对象,每个对象都有一个super属性,创建对象 时分配空间

  • 2.使用

  •  1.修饰父类的成员变量  super.color
    
  •  2.修饰父类的成员方法  super.introduce(); 不要求是第一条语句
    
  •  3.修饰父类的构造方法  super(color,age);   必须是第一条语句
    
  • 3.注意

  • this和super不能同时出现在子类的构造方法中

  • 1.this和super都必须是构造方法的第一条语句,如果都存在,谁是第二条语句多错误

  • 2.更核心的原因:继承条件下对象的创建过程
    */
    public class TestAnimal {
    public static void main(String[] args) {
    Dog dog = new Dog();
    dog.age=3;//从父类继承的属性
    dog.color=“black and blue”;//从父类继承的属性
    dog.nickName=“旺财”;//dog自己的属性
    dog.strain=“拉布拉多犬”;//dog自己的属性
    dog.introduce();

     Dog dog2 = new Dog("黑色", 3, "小强", "雪纳瑞");
     dog2.introduce();
    

// dog.eat();//从父类继承的属性
// dog.sleep();//从父类继承的属性
// dog.introduce();//从父类继承的属性
// dog.guard();//dog自己的方法
}
}

super关键字的作用和使用总结:
(1).作用:表示当前对象的父类对象,每个对象都有一个super属性,创建对象时分配空间
(2).使用
1.修饰父类的 成员变量 super.color
2.修饰父类的 成员方法 super.showInfo(); 不要求是第一条语句
3.修饰父类的 构造方法 super(color,age); 必须是第一条语句
(3).注意
this和super不能同时出现在子类的构造方法中
1.this和super都必须是构造方法的第一条语句,如果都存在,谁是第二条语句多错误
2.更核心的原因:继承条件下对象的创建过程

作业:
(1)理解并掌握继承中的父类及子类的关系,理解 重写、super、理解父类及子类的内存关系图
(2)设计一副扑克牌,给出洗牌的方法,并输出每次洗牌后的牌

(3)编程:设计一个人类作为父类,设计若干个子类(按国籍)
1.静态特征(成员属性):name,sex,age,skin
2.动态方法(成员方法):eat(),speak()

2.23、重写equals方法
示例:
/**

  • == 和 equals的区别

  • == :比较的是栈内存中的值

  • 对于基本数据类型,比较的是栈内存中的值

  • 对于引用数据类型,比较的是栈内存中的值(值的真实含义是一个地址)

  • equals() 比较的对象在堆内存中成员变量的内容

  • Object的equals比较的是地址,作用和==相同

  • public boolean equals(Object obj) {
    return (this == obj);
    } *

  • 子类应该重写Object的equals方法来达到判断内容是否相等的目的
    */
    public class TestAnimal {
    public static void main(String[] args) {
    int num1 =10;
    int num2 =10;
    System.out.println(num1==num2);//true
    //System.out.println(num1.equals(num2));
    //Animal an1 = new Animal(“黑色”, 4);
    //Animal an2 = new Animal(“黑色”, 4);

     Animal an1 = new Animal(new String("黑色2"), 4);
     Animal an2 = new Animal(new String("黑色"), 4);
     System.out.println(an1==an2);//false
     System.out.println(an1.equals(an2));//false
     System.out.println(an2.equals(an1));
     System.out.println(an1.equals(null));
     System.out.println(an1.equals("abc"));
     
     Dog dog1 = new Dog("黑色", 3, "小强", "雪纳瑞");
     Dog dog2 = new Dog("黑色", 4, "小强2", "雪纳瑞2");
     System.out.println(dog1==dog2);//
     System.out.println(dog1.equals(dog2));//	
    

    }
    }

总结:
== 和 equals 的区别 (重要)

  • == :比较的是栈内存中的值
  • 对于基本数据类型,比较的是 栈内存中的值
  • 对于引用数据类型,比较的是 栈内存中的值(值的真实含义是一个地址)
  • equals() 比较的对象在 堆内存 中 成员变量的内容
  • Object的equals比较的是地址,作用和 == 相同
  • public boolean equals(Object obj) {
    return (this == obj);
    }
  • 子类应该重写Object的equals方法来达到判断内容是否相等的目的。

2.24、重写equals的更多内容
==:
比较两个 基本类型 变量的值是否相等
比较两个 引用类型 的值即栈内存中的地址是否相等,即是否指向同一对象。

equals() :
两对象的内容是否一致
示例
object1.equals(object2) 如:p1.equals(p2)
比较所指对象的内容是否一样
是比较两个对象,而非两个基本数据类型的变量

object1 == object2 如:p1==p2
比较p1和p2的值即 栈内存地址 是否相等,即是否是指向同一对象。

自定义类必须重写equals(),否则其对象比较结果总是false。


父类方法的重写的补充:
强调的是 父类 与 子类之间的 多态性的表现!
“==”:方法名、形参列表相同。子类和父类要相同!
“≤≤”:返回值类型和异常类型,子类小于等于父类。(返回值类型?)
补充:返回值类型(子类要等于父类)
“≥”:访问权限,子类大于等于父类

构造方法调用顺序:
根据super的说明,构造方法第一句 总是:super(…)来调用父类对应的构造方法。
先向上追溯到Object,然后再依次向下执行类的初始化块和构造方法,直到当前子类为止。

如果有static 的静态代码块,那么优先依次从上往下执行所有类的 static 的静态代码块,然后再从上往下执行 非静态代码块 以及 构造方法!

类的创建过程总结:
(1)先从上往下依次执行各个父类的静态代码块
(2)先从上往下依次执行各个父类的非静态代码块以及构造器中的代码块
(3)执行其他

2.25、认识组合composite

“is-a”关系使用 继承!
上面的通过在Audi类中增加一个Car属性虽然也复用了代码,但是不合逻辑不容易理解。
Animal <— Dog 共性和特性的一个表达
Person <— Student

“has-a”关系使用 组合!
计算机类,主板类。可以通过在计算机类中增加主板属性来复用主板类的代码!
MainBoard — Computer
Memory — Computer
整体与部分的关系

2.26、引入类的封装
封装(encapsulation)主要介绍的是权限修饰符。
示例讲解:
/**

  • 问题1:person.age= 300; 可以直接访问属性,没有任何的控制,导致数据不合理

  • 问题2:相同的代码,person.name=“zhangsan”; 在不同位置时可能会出现错误

  • 解决:合理的封装。

  • 封装可以从四个方面给大家介绍一下:
    1.什么是封装?好处有哪些
    2.封装涉及的权限修饰符有哪些
    3.如何使用权限修饰符修饰类的成员
    4.如何进行权限修饰符修饰类

  • 1.什么是封装?好处有哪些

  • 汽车

  • 电视机

  • 隐藏某些功能,只对外暴露某些功能

  • 1.降低了使用的难度

  • 2.提高了安全性

  • 2.封装涉及的权限修饰符有哪些

  • private 当前类 类可见性

  • 默认 当前包 包可见性

  • protected 当前包 +其他包中的子类

  • public 当前包+其他包=所有包=当前项目 项目可见性

  • 作用范围越来越大

  • 3.如何使用权限修饰符修饰类的成员

  • 1.对属性的封装

  • 1.属性private private int age;

  • 2.提供public的setter和getter方法 setAge() getAge()

  • 3.在setter方法中添加控制语句

  •  if(age <0 || age>130){
     	this.age = 20;
     	return;
     }
    
  • 2.对于方法的封装

  • 希望外部进行访问的方法,一般定义为public

  • 如何只是用来让本类的方法来调用的辅助方法,并不对外发布,可以定义为private

  • 4.如何进行权限修饰符修饰类

  • 成员的修饰符四个

  • 类的修饰符两个:public 默认

  • 默认:类的范围仅限于当前包

  • public 类的范围所有包 ,此时要求类名和文件名相同
    */
    public class Person {
    private String name;
    private int age;

    public Person(){
    }

    public Person(String name, int age) {
    super();
    this.name = name;
    //this.age = age;
    this.setAge(age);
    }
    public void setName(String name){
    this.name = name;
    }

    public String getName(){
    return name;
    }
    public void setAge(int age){
    if(age <0 || age>130){
    this.age = 20;
    return;
    }
    this.age = age;
    }
    public int getAge(){
    return age;
    }
    private void introduce(){
    //int m = 5+6;
    System.out.println(name+" "+age);
    }
    public void shout(){
    System.out.println(“starting…”);
    introduce();
    System.out.println(“ending…”);
    }

// public static void main(String[] args) {
//
// Person person = new Person();
// person.name=“zhangsan”;
// person.age= 300;
// person.introduce();
// }
}
public class TestPerson {
public static void main(String[] args) {
Person person = new Person();
//person.name=“zhangsan”;//赋值
//person.age= 300;
person.setName(“zhangsan”);
person.setAge(300);
//person.introduce();
person.shout();
//System.out.println(person.name);
//System.out.println(person.age);//输出
System.out.println(person.getName());
System.out.println(person.getAge());
Math math;
}
}

1.什么是封装?好处有哪些
生活举例:

  •   汽车 
    
  •   电视机
    
  •   隐藏某些功能,只对外暴露某些功能
    
  •  1. 降低了类的方法的使用难度
    
  •  2. 提高了数据的安全性
    
  • 2.封装涉及的 权限修饰符 有哪些

  • private 当前类 类可见性

  • 默认 当前包 包可见性

  • protected 当前包 + 其他包中的子类

  • public 当前包 + 其他包=所有包=当前项目 项目可见性

  • 作用范围越来越大

  • 3.如何进行类的成员封装

  • 见下面

  • 4.如何进行类的封装


为什么需要封装?封装的作用和含义?
隐藏对象内部的复杂性,只对外公开简单的接口。
便于外界调用,从而提高系统的 可扩展性、可维护性。
我们程序设计要追求 “高内聚,低耦合”。
高内聚:就是类的内部数据操作细节自己完成,不允许外部干涉;
低耦合:仅暴露少量的方法给外部使用。

2.27、实现类的封装
如何进行类的成员封装?
成员(成员变量或成员方法)访问权限共有四种:
private 私有的
只能被当前类本身访问。(类可见性)

default/friendly 默认的/友好的(包可见性)
被这个类本身访问;被同一个包中的类访问。

protected 受保护的
可以被这个类本身访问;同一个包中的所有其他的类访问;被它的子类(同一个包以及不同包中的子类)访问

public 公共的
可以被项目中所有的类访问。(项目可见性)

3、如何进行类的成员封装: JavaBean

  • 1.对属性的封装

  • 1.属性 private private int age; 私有化

  • 2.提供public的setter和getter方法 setAge() getAge() is/get[boolean]

  • 3.在setter方法中可以添加控制语句,如果有必要的话!

  •  if(age <0 || age>130){
     	this.age = 20;
     	return;
     }
    
  • 2.对于方法的封装

  • 希望外部进行访问的方法,一般定义为public

  • 如果希望本类的某个方法来调用辅助类,并不对外发布,可以定义为private修饰辅助类


类的访问权限只有两种:
public 公共的 可被同一项目中所有的类访问。 (必须与文件名同名)
default/friendly 默认的/友好的 可被同一个包中的类访问。

2.28、完善类的封装

演示1:自动生成相关封装代码的操作 (set/get)

演示2:父类私有属性 子类如何封装?
通过 super()

4.如何进行权限修饰符修饰类

  • 成员的修饰符四个: private 默认/友好的(defaulte) protected public
  • 类的修饰符两个:public 默认
  • 默认:类的范围仅限于当前包
  • public 类的范围所有包 ,此时要求类名和文件名相同

封装要点(PPT):

类的属性的处理:
一般使用 private. (除非本属性确定会让子类继承)
提供相应的get/set方法来访问相关属性. 这些方法通常是public,从而提供对属性的读取操作。(注意:boolean变量的get方法是用:is开头!)

一些只用于本类的辅助性方法可以用 private,希望其他类调用的方法用public

示例
import com.bjsxt.oop.encapsulation.Person;
public class Student extends Person {
private String stuNo;
private String schoolName;

public Student() {
	super();
}
public Student(String stuNo, String schoolName) {
	super();
	this.stuNo = stuNo;
	this.schoolName = schoolName;
}

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

// //this.name = name;
// //this.age = age;
super.setName(name);
super.setAge(age);
// super(name,age);
// this.stuNo = stuNo;
// this.schoolName = schoolName;
// }
public String getStuNo() {
return stuNo;
}
public void setStuNo(String stuNo) {
this.stuNo = stuNo;
}
public String getSchoolName() {
return schoolName;
}
public void setSchoolName(String schoolName) {
this.schoolName = schoolName;
}

public void study(){
	System.out.println(super.getAge()+ super.getName());
}

}
public class Person {
private String name;
private int age;

public Person(){
}

public Person(String name, int age) {
	super();
	this.name = name;
	//this.age = age;
	this.setAge(age);
}
public void setName(String name){
	this.name = name;
}
public String getName(){
	return name;
}
public void setAge(int age){
	if(age <0 || age>130){
		this.age = 20;
		return;
	}
	this.age = age;
}
public int getAge(){
	return age;
}
private void introduce(){
	//int m = 5+6;
	System.out.println(name+"  "+age);
}
public void shout(){
	System.out.println("starting.....");
	introduce();		
	System.out.println("ending......");
}

// public static void main(String[] args) {
//
// Person person = new Person();
// person.name=“zhangsan”;
// person.age= 300;
// person.introduce();
// }
}
public class TestPerson {
public static void main(String[] args) {
Person person = new Person();
//person.name=“zhangsan”;
//person.age= 300;
person.setName(“zhangsan”);
person.setAge(30);
//person.introduce();
//System.out.println(person.name);
//System.out.println(person.age);//输出
System.out.println(person.getName());
System.out.println(person.getAge());

	Person person2 = new Person("小红", 200);
	person2.shout();
	System.out.println(person2.getAge());
}

}

作业:
(1)充分理解 == 与 equals 的区别 (重点!)
(2)充分理解封装、四大权限修饰符的特点及应用场合

课堂作业:
(1)老师类:属性:姓名、性别、工资、学科
方法:自我介绍、上课()
(2)医生类:属性:姓名、性别、工资、职称、科室
方法:自我介绍、诊断()
(3)公务员:属性:姓名、性别、工资、职位
方法:自我介绍、考察()

2.29、继承和封装案列_封装动物类
继承和封装案列_封装动物类
需求: 见 PPT
1.鱼类 属性 :年龄 重量
方法:自我介绍 游泳
2.鸟类 属性:年龄 颜色
方法:自我介绍 飞
分析:
使用继承:
抽取出动物类:属性(年龄) 方法(自我介绍)
鱼类继承动物类,提供特有属性 重量 和 特有方法 游泳
鸟类继承动物类,提供特有属性 颜色 和 特有方法 飞
开发测试类,进行测试

使用封装
属性私有、方法public ,提供对应的构造方法

示例:
public class Animal extends Object{
//属性
private int age;
//构造方法
public Animal(){

}
public Animal(int age){
	//this.age = age;
	this.setAge(age);
}
//方法
public void setAge(int age){
	if(age<=0 || age>6){
		this.age = 2;
	}else{
		this.age = age;
	}
}
public int getAge(){
	return age;
}
public void introduce(){
	System.out.println("我今年"+age+"岁了");
	
}
@Override
public String toString() {
	return "Animal [age=" + age + "]";
}

@Override
public boolean equals(Object obj) {
	//如果两个对象时同一个对象,返回true
	if (this == obj)
		return true;
	//如果参数是null,直接返回false
	if (obj == null)
		return false;
	//obj instanceof Animal
	 //如果两个对象的类型不同,直接返回false
	if (this.getClass() != obj.getClass())//Animal
		return false;
	//如果不是同一个对象,如果参数不是null,如果类型相同
	//强制转换,并比较属性值是否相同
	Animal other = (Animal) obj;		
	if (this.age != other.age)
		return false;
	return true;
}
protected Animal showInfo() throws Exception{
	return null;
}

}
public class Bird extends Animal{
//属性
private String color;
public Bird() {
super();
}
public Bird(int age, String color) {
super(age);
this.color = color;
}
//方法
public void fly(){
System.out.println(“我在空中展翅高翔”);
}
@Override
public void introduce() {
System.out.println(“我是一只”+color+“的鸟”);
super.introduce();
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
//return super.toString()+" Bird [color=" + color + “]”;
return " Bird [color=" + color + “,age=”+super.getAge()+"]";
}

@Override
public boolean equals(Object obj) {
	if (this == obj)
		return true;
	//重用父类animal的equals方法
	if (!super.equals(obj))
		return false;
	if (getClass() != obj.getClass())//Bird
		return false;
	Bird other = (Bird) obj;
	if (color == null) {
		if (other.color != null)
			return false;
	} else if (!color.equals(other.color))//此时不能使用== color是引用类型String
		return false;
	return true;
}
public Bird showInfo() throws RuntimeException{
	return null;
}

}
public class Fish extends Animal{
private int weight;

public Fish() {
	super();
}
public Fish(int age, int weight) {
	super(age);
	this.weight = weight;
}
public int getWeight() {
	return weight;
}
public void setWeight(int weight) {
	this.weight = weight;
}

@Override
public void introduce() {
	System.out.println("我是一只"+weight+"斤重的鱼");
	super.introduce();
}
public void swim(){
	System.out.println("我在水里悠闲吐泡");
}

@Override
public String toString() {
	return "Fish [weight=" + weight + ",age="+super.getAge()+"]";
}
@Override
public boolean equals(Object obj) {
	if (this == obj)
		return true;
	if (!super.equals(obj))
		return false;
	if (getClass() != obj.getClass())
		return false;
	Fish other = (Fish) obj;
	if (weight != other.weight)
		return false;
	return true;
}

}
/**

  • 总结:
  • 1.继承
  • public class Bird extends Animal
  • 2.重写
  • public void introduce() {}
  • public String toString() {}
  •                 public   boolean   equals(Object obj) throw Excpetion { 。。。。}
    
  •                 权限修饰符 返回值类型  方法名  参数列表   异常类型  方法体
    

方法重载/overload/同一个类内部 无关 无关 == <> 无关 <>
方法重写/override/子类和父类之间 >= <= == == <= <>
*
3.子类能够从父类继承哪些“财产”??

  • 是所有的吗???不是
    1.private肯定无法继承
    2.构造方法肯定无法继承
    3.public肯定可以继承
    4.protected肯定可以继承
    5.默认权限修饰符的成员变量和方法能继承吗???如果子类父类在同一个包中,可以继承,否则无法继承 *
    /
    public class Test {
    public static void main(String[] args) {
    Bird bird = new Bird(4,“红色”);
    bird.introduce();
    bird.fly();
    //System.out.println(bird);
    System.out.println();
    Fish fish = new Fish(2, 5);
    fish.introduce();
    fish.swim();
    }
    }
    /
    *
  • 1.封装
  • 1.封装的好处:降低使用难度,提高安全性
  • 2.成员的权限修饰符 private 默认 protected public
  • 3.如何进行封装:属性private,提供public的setter和getter方法,setter方法中添加控制语句
  • 4.类的权限修饰符:默认和public
    */
    public class TestAnimal {
    public static void main(String[] args) {
    Animal an1 = new Animal();
    an1.setAge(4);
    System.out.println(an1.getAge());
    int age =an1.getAge();
    System.out.println(age);
    Animal an2 = new Animal(22);
    System.out.println(an2.getAge());
    an2.introduce();
    }
    }

2.30、继承和封装案例_继承和重写

主要讲解使用快捷方式,自动生成 toString() 、equals()方法

2.31、继承和封装案例_继承和重写总结
1.继承

  • public class Bird extends Animal
    2.重写(方法重载与重写的区别,重要!!!)
  • public void introduce() {}
  • public String toString() {}

(方法重载与重写的区别,重要!!!)

  • 见下表

子类能够从父类继承哪些“财产”??

  • 是所有的吗???-- 不是
  • 1.private肯定无法继承
  • 2.构造方法肯定无法继承 – 不参与继承
  • 3.public肯定可以继承
  • 4.protected肯定可以继承
  • 5.默认权限修饰符的成员变量和方法能继承吗???
    如果子类父类在同一个包中,可以继承,否则无法继承

封装总结:

  • 1.封装的好处:降低使用难度,提高安全性,是代码逻辑独立(归一原则)

  • 2.成员的权限修饰符: private 、 默认 、 protected 、 public

  • 3.如何进行封装:
    属性private,提供public的setter和getter方法,setter方法中添加控制语句

  • 4.类的权限修饰符:默认 和 public
    默 认:类的范围仅限于当前包。
    public:类的范围所有包,此时要求类名和文件名相同。

方法重载与重写的区别!(重要的点!)
public boolean equals (Object obj) throw Excpetion {}
权限修饰符 返回值类型 方法名 参数列表 异常类型 方法体
方法重载overload 同一个类内部 无关 无关 == <> 无关 <>
方法重写override 子类和父类之间 >= <= == == <= <>

2.32、引入和实现多态
PPT - 简单引入概念 多态 polymorphism
多态性是OOP中的一个重要特性,主要是用来实现动态联编的,换句话说,就是程序的最终状态只有在执行过程中才被决定而非在编译期间就决定了。这对于大型系统来说能提高系统的灵活性和扩展性。

简单描述: 多态就是对象的多种形态。

java中如何实现多态?使用多态的好处?
引用变量的两种类型:
编译时类型(模糊一点,一般是一个父类)
由声明时的类型决定。
运行时类型(运行时,具体是哪个子类就是哪个子类)
由实际对应的对象类型决定。

多态的存在要有3个必要条件:
要有继承,要有方法重写,父类引用指向子类对象
父类的引用调用重写的方法

1.什么是多态

  • 多种形态
  • Person p1 = new Chinese();//特殊在哪里:编译类型是Person 运行类型Chinese
  • p1.eat();
  • 将子类对象赋给父类的引用变量,然后通过父类引用变量调用子类重写的方法
  • 多态就出现了

2.多态的条件 注意:多态和方法有关,和属性无关

  • 1.继承 Person Chinese
  • 2.方法重写 eat()
  • 3.将子类对象赋给父类引用变量 Person p1 = new Chinese();

使用多态的时候要注意:如果我们在子类中编写一个独有的方法(没有继承父类的方法),此时就不能通过父类的引用创建的子类对象来调用该方法!!!
注意: 继承是多态的基础。

示例代码:Person Chinese English
//多态和方法有关,和属性无关
public class Person {
//属性
//子类继承的方法
public void sleep(){
System.out.println(“闭上眼睛就睡觉呀”);
}
//子类重写的方法
public void eat(){
System.out.println(“张开嘴巴就吃饭呀”);
}
}

public class English extends Person{
//从父类继承的 sleep
//重写父类的方法
public void eat(){
System.out.println(“English eating meat by knife”);
}
//子类特有的方法
public void raceHorse(){
System.out.println("English like horse racing ");
}
}

public class Chinese extends Person{
//从父类继承的 sleep
//重写父类的方法
public void eat(){
System.out.println(“Chinese eating rice by chopstick”);
}
//子类特有的方法
public void playTj(){
System.out.println(“Chinese play shadowBox every morming”);
}
}

public static void main(String[] args) {
// Person person = new Person();
// person.eat();
// person.sleep();
// System.out.println();
// //
// Chinese ch = new Chinese();
// ch.sleep();
// ch.eat();
// ch.playTj();

	//多态闪亮登场了
	Person p1 = new Chinese();//特殊在哪里:运行类型Chinese 编译类型是Person
	Person p2 = new English();
	p1.sleep();
	p2.sleep(); //不是多态,是单态
	
	//p1.playTj(); 无法访问子类特有的方法
	//p2.raceHorse(); //不是多态 无态
	p1.eat();
	p2.eat();//此乃多态也
}

2.33、使用多态的好处
多态的好处一:使用父类作为方法的形参,达到功能扩展的效果!

例子:基于上面的代码例子,增加 食堂类 Canteen.java

食堂类
缺点1:showEat()太多了,每个子类都要提供一个showEat()
缺点2:每增加一个子类,都要修改Canteen类源代码,增加一个showEat(),不符合开闭原则

解决:多态

  • 优点1:showEat()一个就够了,使用父类做参数,减少了代码量
  • 优点2:增加子类,不需要修改Canteen类源代码,有利于代码扩展

总结:
3.多态的好处
* 1.减少代码量
* 2.利于代码扩展

4.多态使用最多的场合

  • 使用父类做方法形参

5.多态所涉及的技术点

  • 1.向上转型 – 将子类对象赋给父类引用变量
  •  Person p1 = new Chinese();
    
  • 2.向下转型 – 将父类引用变量赋给子类引用变量
    Chinese ch = (Chinese)p1;
  • 就可以调用子类特有的方法了
    
  • 基本数据类型的类型转换
  • 引用数据类型的类型转换(向上转型 向下转型)

6.其他
1.多态和方法有关,和属性无关
2.多态的另外一个使用场合:使用父类做返回值类型 (工厂模式)

扩展知识点:
开闭原则(Open Close Principle,缩写:OCP),软件中的对象(类、模块、函数等)应该对于扩展是“开放”的,但是对于修改是“封闭”的。通俗点讲就是软件系统中包含的各种组件应该在不修改现有代码的基础上引入新功能。
“开”是对于组件功能的扩展是开放的,是允许对其进行功能扩展的;
“闭”是对于原有代码的修改是封闭的,即不应该修改原有代码。

2.34、多态_向上转型

多态总结:
向上类型转换(隐式/自动类型转换),是小类型转换到大类型。
1、多态的体现
父类的引用指向了自己的子类对象 Animal an = new dog();
父类的引用也可以接收自己的对象
2、多态的前提
必须是类与类之间的关系,要么继承或实现
通常还有一个前提,存在覆盖 (重写)
3、多态的好处
多态的出现大大的提高了程序的扩展性
4、多态的弊端
只能使用父类的引用访问父类的成员
5、多态的应用

  • 1、多态和方法有关,与属性无关
  • 2、多态的另外一个使用场合,使用父类作返回值
    使用父类作为参数
    6、注意事项

向上转型

  • Person person = new Chinese();将子类对象赋给父类引用变量,自动转换

  • person.sleep(); 调用的子类继承父类的方法

  • person.eat(); 调用的是子类重写的方法,而不是父类的方法

  • person.playTj();不能调用子类特有的方法

  • 理解:工厂招工人,是人就可以,不分国籍

  • Person person = new Chinese(); 工厂招工,不分国籍,中国人满足要求,自动转换

  • person.sleep(); 中午休息,中国人 英国人 意大利人睡觉的方式都是一样

  • person.eat(); 中午到食堂吃饭时,原形毕露,自己的吃饭方式

  • person.playTj(); 老板不能直接找个员工就让他playTj,因为这个员工可能是个英国人或者意大利人呢

2.35、多态_向下转型
向下转型
 向下类型转换(强制类型转换),是大类型转换到小类型(有风险,可能出现数据溢出)。

    1. 必须强制类型转换
      *2. 不是做手术,必须强制转换成真实子类型,否则就会出现类型转换异常ClassCastException
  • java.lang.ClassCastException: English cannot be cast to Chinese
    at com.bjsxt.oop.polymorphism.TestPoly3.main(TestPoly3.java:23)
  • 3.为了避免类型转换异常,可以在强转之前进行判断 instanceof
  • p instanceof Chinese
  • 对象 instanceof 类名或者接口名
  • 4.instanceof辨析 //画图
  • System.out.println(p instanceof Chinese);//true
    System.out.println(p instanceof English);//false
    System.out.println(p instanceof Person);//true
    System.out.println(p instanceof Object);//true
    //System.out.println(p instanceof String);//

3. instanceof运算符,来解决引用对象的类型,避免类型转换的安全性问题。
instanceof是Java的一个二元操作符,和==,>,<是同一类东东。由于它是由字母组成的,所以也是Java的保留关键字。它的作用是测试它左边的对象是否是它右边的类的实例,返回boolean类型的数据。

注意:
使用instanceof的注意事项:
对象的编译类型(Person)必须和instanceof后面的类在继承树上有上下级继承关系才可以。

补充说明:在比较一个对象是否和另一个对象属于同一个类实例的时候,我们通常可以采用instanceof和getClass两种方法通过两者是否相等来判断,但是两者在判断上面是有差别的。Instanceof进行类型检查规则是:你属于该类吗?或者你属于该类的派生类吗?而通过getClass获得类型信息采用==来进行检查是否相等的操作是严格的判断,不会存在继承方面的考虑;
总结:在写程序的时候,如果要进行类型转换,我们最好使用instanceof运算符来判断它左边的对象是否是它右边的类的实例,再进行强制转换。

示例:
/**

  • 向上转型

    • Person person = new Chinese();将子类对象赋给父类引用变量,自动转换
    • person.sleep(); 调用的子类继承父类的方法
    • person.eat(); 调用的是子类重写的方法,而不是父类的方法
    • person.playTj();不能调用子类特有的方法
  • 理解:工厂招工人,是人就可以,不分国籍

    • Person person = new Chinese(); 工厂招工,不分国籍,中国人满足要求,自动转换
    • person.sleep(); 中午休息,中国人 英国人 意大利人睡觉的方式都是一样
    • person.eat(); 中午到食堂吃饭时,原形毕露,自己的吃饭方式
      person.playTj(); 老板不能直接找个员工就让他playTj,因为这个员工可能是个英国人或者意大利人呢
      /
      public class TestPoly2 {
      public static void main(String[] args) {
      //基本数据类型的类型转换
      double d = 5;//自动转换
      System.out.println(d);
      Person person = new English();//自动转换
      person.sleep();//单态
      person.eat();//多态
      //person.playTj();//无态
      }
      }
      /
      *
  • 向下转型

    1. 必须强制类型转换
    1. 不是做手术,必须强制转换成真实子类型,否则就会出现类型转换异常ClassCastException
  • java.lang.ClassCastException: English cannot be cast to Chinese
    at com.bjsxt.oop.polymorphism.TestPoly3.main(TestPoly3.java:23)

  • 3.为了避免类型转换异常,可以在强转之前进行判断 instanceof

  • p instanceof Chinese

  • 对象 instanceof 类名或者接口名

  • 4.instanceof辨析

  • System.out.println(p instanceof Chinese);//true
    System.out.println(p instanceof English);//false
    System.out.println(p instanceof Person);//true
    System.out.println(p instanceof Object);//true
    //System.out.println(p instanceof String);//
    使用instancof的注意事项:对象的编译类型(Person)必须和instanceof后面的类在继承树上有上下级继承关系才可以
    */
    public class TestPoly3 {
    public static void main(String[] args) {
    //基本数据类型的类型转换
    double d = 5;
    System.out.println(d);
    int i = (int)(d+4.4);//强制转换 并且做手术
    System.out.println(i);

    //引用数据类型的类型转换:向下转型
    Person p = new Chinese();//向上转型 
    //Person p = new English();
    //p.playTj();// 不能访问子类特有的方法
    //Chinese ch = (Chinese)p;//强制类型转换  不是做手术,必须强制转换成真实子类型
    //ch.playTj();
    if(p instanceof Chinese){
    	Chinese ch = (Chinese)p;
    	ch.playTj();
    }else if(p instanceof English){
    	English en = (English)p;
    	en.raceHorse();
    }else if(p instanceof Italian){
    	Italian it = (Italian)p;
    	it.playfootball();
    }
    
    System.out.println(p instanceof Chinese);//true
    System.out.println(p instanceof English);//false
    System.out.println(p instanceof Person);//true
    System.out.println(p instanceof Object);//true
    //System.out.println(p instanceof String);//
    

    }
    }

使用instancof的注意事项:对象的编译类型(Person)必须和instanceof后面的类在继承树上有上下级继承关系才可以,如下图:

2.36、多态_简单工厂模式
多态的另外一个使用场合:使用父类做返回值类型

如果把 TestPoly5 该类比作是一个公司,

  • Person p1 = new Chinese(); 意味着公司花很大精力培养了 一个人
  • p1.sleep();
    p1.eat(); 工人到了公司的工作和生活
  • 问题:公司既要培养人又要让他工作
  • 解决思路:把培养人的工作交给学校或者培训机构完成,只要招聘人才即可,不需要培训

School.java
.多态的另外一个使用场合:使用父类做返回值类型

  • 设计模式:简单工厂模式
  • 工厂类负责生产各种产品
  • 用户只要购买产品即可,而不需要生产产品。

示例
/**

  • 如果把该类比作是一个公司,

  • Person p1 = new Chinese(); 意味着公司花很大精力培养了 一个人

  • p1.sleep();
    p1.eat(); 工人到了公司的工作和生活

  • 问题:公司既要培养人又要让他工作

  • 解决思路:把培养人的工作交给学校或者培训机构完成,只要招聘人才即可,不需要培训
    */
    public class TestPoly5 {
    public static void main(String[] args) {
    //Person p1 = new Chinese();//花很大精力培养一个人
    Person p1 = School.getPerson(“ch”);//直接招聘一个人
    p1.sleep();
    p1.eat();

     //Person p2 = new English();
     Person p2 = School.getPerson("en");
     p2.sleep();
     p2.eat();
     
     //Person p3 = new Italian();
     Person p3 =  School.getPerson("it");
     p3.sleep();
     p3.eat();
    

    }
    }
    /**

  • .多态的另外一个使用场合:使用父类做返回值类型

  • 设计模式:简单工厂模式

  • 工厂类负责生产各种产品

  • 用户只要购买产品即可,而不需要生产产品
    */
    public class School {
    public static Person getPerson(String type){
    // if(type.equals(“ch”)){
    // return new Chinese();
    // }else if(type.equals(“en”)){
    // return new English();
    // }else{
    // return new Italian();
    // }
    或者如下写法:
    Person p;
    if(type.equals(“ch”)){
    p= new Chinese();
    }else if(type.equals(“en”)){
    p= new English();
    }else{
    p =new Italian();
    }
    return p;
    }
    }

2.37、使用final开发Math

示例
/**

  • 算术类
  • 1.加法运算
  • 2.计算圆的周长和面积
  • 3…
  • 技能点:final
  • 1.final的含义
  • final----finally 最后的 最终的 不变的
  • 2.final的使用
  • 1.修饰变量 变量的值不能再变化 变成常量
  •  public static final double PI = 3.14159;
    
  •  public 当前包和其他包的类都可以访问
    
  •  static 可以通过类名直接访问
    
  •  final  值不能再变化
    
  •  double 常量类型
    
  •  PI  常量名
    
  •  =  赋值运算符
    
  •  3.14159  常量值
    
  • 2.修饰方法
  • 方法不能被子类重写
    
  • 3.修饰类
  •  不能再由子类继承
    
  • 3.JDK提供的final类 final方法 final属性
  •  Math
    
  • 	String StringBuffer
    

*/
public final class Maths {
// private Maths(){
//
// }
public static final double PI = 3.14159;

public static int add(int num1,int num2){
	return num1+num2;
}

public static final double clength(double r ){
	//final double pi = 3.14;//局部变量
	//pi=3.14159;
	double length = PI * 2 * r;
	return length;
}

public static double carea(double r){
	//final double pi = 3.14159;
	double area = PI*r*r;
	return area;
}

}
public class TestMaths {
public static void main(String[] args) {
//Maths maths = new Maths();
//System.out.println(maths.PI);
System.out.println(Maths.PI);
System.out.println(Maths.add(5, 3));
System.out.println(Maths.clength(1));
System.out.println(Maths.carea(3));
}
}

算术类

  • 1.final的含义

  • final----finally 最后的 最终的 不变的

  • 2.final的使用

  • 1.修饰变量 变量的值不能再变化 变成常量

  •  public static final double PI = 3.14159;
    
  •  public 当前包和其他包的类都可以访问
    
  •  static 可以通过类名直接访问
    
  •  final  值不能再变化
    
  •   double 常量类型
    
  •   PI  常量名
    
  •   =  赋值运算符
    
  •  3.14159  常量值
    
  • 2.修饰方法

  • 方法不能被子类重写。
    
  • 3.修饰类

  • 不能再由子类继承。
    
  • 3.JDK提供的 final类 final方法 final属性

  • 常见类:Math、String 、StringBuffer

作业:
(1)熟练掌握 多态的特点及使用场合
(2)了解 简单工厂模式
(3)掌握并熟练运用 多态的 向上转型 、 向下转型 概念、怎么用?
(4)掌握 final 的特点及运用

作业:定义一个 水果罐头工厂类(模仿 简单工厂模式)
提供一个方法:通过不同的水果,生产出不同的罐头
定义 水果 父类
属性(重量、颜色、品种)
方法(自我介绍)
水果子类(苹果、香蕉、水蜜桃等不限定,可以自由发挥)

作业:
知识扩展:
final、finally、finalize 区别和含义?
String、StringBuffer、StringBuilder的区别及关系

2.38、抽象类和抽象方法
PPT介绍概念
举例讲解:Animal.java / Dog.java / Test.java

  • 问题1:Animal an = new Animal();没有一种生物名称是Animal,创建对象没有意义
  •    拒绝创建对象
    
  • 解决:将Animal类定义为 抽象类 abstract
  • 抽象类不能实例化,只能被继承
  • 问题2:dog可以重写shout,也可以不重写;希望dog类必须重写shout方法,不重写编译错误
  • 解决:将Animal的shout()定义为抽象方法
  •   抽象方法只有声明,没有实现!
    

抽象类总结:
1.语法:

  • 1.抽象类和抽象方法都是使用abstract修饰
  • 2.抽象类不能new,只能被继承
  • 3.抽象类必须有构造方法,创建子类对象时需要
  • 4.抽象类可以有0,1或者多个抽象方法
  • 5.抽象方法只有声明,没有实现
  • 6.public abstract void shout() { }不是抽象方法
  • 7.子类必须重写抽象方法,如果不重写,还是抽象类

2.意义

  • 抽象类为所有子类提供了一个通用模版,子类可以在这个模版基础上进行扩展。
    通过抽象类,可以避免子类设计的随意性。
    通过抽象类,我们就可以做到严格限制子类的设计,使子类之间更加通用。
    抽象类就是用来当父类的,用来被继承的。
    抽象类可以继承抽象类
    抽象类可以继承普通类吗?? 可以,但是很少这么做

3.其他

  • abstract的反义词 – final最终的

  • final可以修饰 变量,方法和类, 不能修饰 构造方法

  • 修饰变量,则变量不可以被改变

  • 修饰方法,则方法不可以被重写

  • 修饰类, 则类不可以被继承

  • 注意:abstract可以修饰 方法和类,不能修饰 变量和 构造方法

abstract 修饰类 类必须要被继承 类不可以被实例化
abstract 修饰方法 抽象方法 必须被重写
abstract 不能修饰成员变量,编译报错

示例:
public abstract class Animal {
private String color;
public Animal() {
super();
}
public Animal(String color) {
super();
this.color = color;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
// public void shout(){
// System.out.println(“用口发出声音”);
// }
public abstract void shout();
public abstract void eat();
}
public class Dog extends Animal{
public Dog() {
super();
}
public Dog(String color) {
super(color);
}
public void shout(){
System.out.println(“汪汪汪”);
}
@Override
public void eat() {
}
}
/**

  • 问题1:Animal an = new Animal();没有一种生物名称是Animal,创建对象没有意义
  • 拒绝创建对象
    
  • 解决:将Animal类定义为抽象类
  •  抽象类不能实例化,能被继承
    
  • 问题2:dog可以重写shout,也可以不重写;希望dog类必须重写shout方法,不重写编译错误
  • 解决:将Animal的shout()定义为抽象方法
  • 抽象方法只有声明,没有实现
    */
    public class Test {
    public static void main(String[] args) {
    //Animal an = new Animal();
    //an.shout();
    Dog dog = new Dog(“黑色”);
    dog.shout();
    }
    }

2.39、引入接口
先引出概念
接口 interface,和 类,抽象类 是同一个级别的概念.

直接举例讲解
例子:飞机、鸟、超人 飞/睡觉
业务:举行飞行比赛,参加者Bird,Plane,Superman,共同点,都能fly
希望把fly提取出来,如何设计

方案1:定义类Fly,有方法fly。不可以
1.Bird extends Animal,Java只支持单继承
2.Bird extends Animal
Chinese extends Person 继承表达is-a的关系

方案2:定义接口Flyable 接口表达不是is-a关系,是has-a的关系

接口总结:
1.基本语法

  • 1.接口 interface,和类,抽象类是同一个级别的概念
  • 2.接口中所有的方法都是 抽象方法,方法都默认采用 public abstract 修饰,可以省略
  • 3.接口中只有常量,没有变量。所有的常量都是 全局静态常量 public static final
  • 4.接口不能有构造方法
  • 5.接口是不能new

2.如何定义接口

  • public interface Flyable{ }

3.如何实现接口

  • public class Bird extends Animal implements Flyable,Sleepable
  • public class SuperMan implements Flyable,Sleepable
  • 一个类只可以继承一个父类,但是可以同时实现多个接口
  • 必须 先 继承父类 再 实现接口 (亲爹和干爹)

示例:
public class Animal {
public void eat(){
System.out.println(“口吃”);
}
}
public class Bird extends Animal implements Flyable,Sleepable{
public void eat(){
System.out.println(“口吃虫子”);
}
@Override
public void fly() {
System.out.println(“bird展翅高飞”);
}
@Override
public void sleep() {
System.out.println(“bird sleep on the tree”);
}
}
/**

  • 总结接口
  • 1.基本语法
    • 1.接口 interface,和类,抽象类是同一个级别的概念
    • 2.接口中所有 的方法都是抽象方法,方法都默认采用public abstract 修饰,可以省略
    • 3.接口中只有常量,没有变量。所有的常量都是全局静态常量public static final
      1. 接口不能有构造方法
    • 5.接口是不能new
  • 2.如何定义接口
  • public interface Flyable {
  • }
  • 3.如何实现接口
  • public class Bird extends Animal implements Flyable,Sleepable
  • public class SuperMan implements Flyable,Sleepable
  • 一个类只可以继承一个父类,但是可以同时实现多个接口
  • 必先继承父类再实现接口*

*4.使用接口做方法的形参,实参可以是实现了该接口的所有类,可以达到多态的效果

  • 面向接口的开发
  • 对于容易发生变化的内容,在进行设计的时候,先设计成接口,再给出不同的实现
  • 开发时针对接口进行开发,而不是针对实现类进行开发

*5.抽象类和接口的联系和区别(重点)

  • 共同点:
    • 都可以有抽象方法
    • 都不能new
    • 都是用来被子类继承或者实现的
  • 区别1:语法
  •  1.成员变量   接口只有常量,没有变量
    
  • 2.成员方法 接口的方法全部是抽象方法,抽象类可以0个,1个或者多个抽象方法
  • 3.构造方法 抽象类有构造方法,接口没有构造方法
  • 4.一个类只能继承一个抽象类,但是可以同时实现多个接口
  • 区别2:语义(设计理念的区别 核心区别)
  • 抽象类:is-a Bird is a Animal 中间产品 最终产品 模板
  • 接口:has-a Plane/Bird/SuperMan has an flyable ability 具有什么能力 遵守什么规范

*6.接口对Java的单继承 进行了强化

  • 1.Java 单继承 优点:安全 不危险 缺点:功能弱
  • 2.c++ 多继承 好处 功能强大 缺点:危险 不安全(如果两个父类有相同的方法,如果继承了又没有重写,调用的是哪一个??)
  • 3.接口对Java的单继承进行了强化,增加了功能,但是没有危险性(两个接口有相同的方法,子类必须重写,调用的是自己的)
    1. 子类 extends 父类 Bird extends Animal
  • 类 implements 接口 Bird implements Flyable
  • 子接口 extends 父接口
    public interface Flyable extends Sleepable,Serializable,Comparable

*7.实现了接口后创建子类对象时过程有无变化
*public class Bird extends Animal implements Flyable,Sleepable
*
*Bird bird = new Bird();

  • Object—Animal—Bird
    没有任何变化 接口和类不是继承关系,接口也没有构造方法!!!
    /
    public interface Flyable {
    public static final double height=300;
    // public Flyable(){
    //
    // }
    public abstract void fly();
    }
    public interface Sleepable {
    public void sleep();
    }
    public class SuperMan implements Flyable,Sleepable{
    @Override
    public void fly() {
    System.out.println(“超人能飞多高呀?????”);
    }
    @Override
    public void sleep() {
    System.out.println(“超人在天上脑袋朝下睡”);
    }
    }
    /
  • 接口和类,抽象类是同一个级别的概念
  • 业务:举行飞行比赛,参加者Bird,Plane,Superman,共同点,都能fly
  •  希望把fly提取出来,如何设计
    
  • 方案1:定义类Fly,有方法fly。不可以
  • 1.Bird extends Animal,Java只支持单继承
  • 2.Bird extends Animal Chinese extends Person 继承表达is-a的关系
  • 方案2:定义接口Flyable 接口表达不是is-a关系,是has-a的关系
    */
    public class Test {
    public static void main(String[] args) {
    //Flyable f = new Flyable();
    //System.out.println(Flyable.height);
    //Flyable.height = 400;
    Bird bird = new Bird();
    //bird.fly();//自己练习飞行
    showFly(bird);//Flyable f = new Bird();
    Plane plane = new Plane();
    //plane.fly();
    showFly(plane);
    SuperMan sm = new SuperMan();
    //sm.fly();
    showFly(sm);
    Flyable f = new Bird();
    showFly(f);
    }
    public static void showFly(Flyable f){
    f.fly();
    }

// public static void showFly(Bird bird){
// bird.fly();
// }
//
// public static void showFly(Plane plane){
// plane.fly();
// }
//
// public static void showFly(SuperMan sm){
// sm.fly();
// }

}

2.40、接口语法和作用总结
讲解:定义好接口,并实现了相关类,则开始测试

为每一个类定义一个方法,实现飞行的方法 showFly(Bird/Plane/SuperMan)
问题:方法太多
解决:使用接口做方法的形参,实参可以是实现了该接口的所有类,可以达到多态的效果。

(连上)
4.使用接口做方法的形参,实参可以是实现了该接口的所有类,可以达到多态的效果

  • 面向接口的开发
  • 对于容易发生变化的内容,在进行设计的时候,先设计成接口,再给出不同的实现
  • 开发时针对接口进行开发,而不是针对实现类进行开发.

5.抽象类和接口的联系和区别(重点)(直接总结)
共同点:

  • 都可以有抽象方法 也可以没有抽象方法
  • 都不能new
  • 都是用来被子类 继承 或者 实现的

区别1:语法

  • 1.成员变量 接口只有常量,没有变量
  • 2.成员方法 接口中的方法全部是抽象方法,抽象类可以0个,1个或者多个抽象方法,并且允许存在非抽象的方法。
  • 3.构造方法 抽象类有构造方法,接口没有构造方法
  • 4.一个类只能继承一个抽象类,但是可以同时实现多个接口

区别2:语义(设计理念的区别 核心区别)
抽象类:is-a Bird is a Animal 中间产品 最终产品 模板 作为父类
接 口:has-a Plane/Bird/SuperMan has an flyable ability 具有什么能力 遵守什么规范

6.接口对Java的单继承 进行了强化 (直接总结)
1.Java 单继承 优点:安全 不危险 缺点:功能弱
2.c++ 多继承 好处 功能强大 缺点:危险 不安全
(如果两个父类有相同的方法,如果继承了又没有重写,调用的是哪一个??)
3.接口对Java的单继承进行了强化,增加了功能,但是没有危险性(两个接口有相同的方法,子类必须重写,调用的是自己的)
4. 子类 extends 父类 Bird extends Animal

  • 类 implements 接口 Bird implements Flyable
    *子接口 extends 父接口
    抽象类 implements 接口

接口不能继承多个接口? (可以)
public interface Flyable extends Sleepable,Serializable,Comparable

7.实现了接口后,创建子类对象时过程有无变化 (直接总结)
*public class Bird extends Animal implements Flyable,Sleepable
*Bird bird = new Bird();

  • Object—Animal—Bird
  • 注意:没有任何变化 接口和类不是继承关系,接口也没有构造方法!

练习
接口练习_手机设计方案 参考PPT
需求说明:
原始的手机,可以发短信,通电话。
随着发展,手机增加了功能:音频、视频播放、拍照、上网。
分析:
定义手机抽象类HandSet
定义照相、上网,播放接口
制作具体手机并使用

作业:
(1)充分理解 抽象类、接口的概念、区别及应用场合
(2)接口练习_手机设计方案

2.41、内部类的引入和作用

  1. 类的成员(6大成员)
    三大
  • 成员变量
  • 成员方法
  • 构造方法
    三小
  • 静态代码块
  • 代码块
  • 内部类

2.内部类

  • 1.内部类是类的成员,所以可以是使用 四个权限修饰符 进行修饰
  • 2.内部类方法可以直接访问外部类的成员变量和方法
  • 3.外部类方法中不能直接访问内部类的属性和方法,可以间接访问(先创建内部类对象)
    4.成员内部类不能定义静态成员,但是可以定义final的静态成员属性

3.内部类的作用

  • 1.可以定义比private权限更小的作用范围
  • 2.通过内部类可以实现多重继承(了解即可)

4.内部类的编译结果

  • OuterClass.class
  • OuterClass$InnerClass.class

5.外部类,内部类,内部类方法中有同名变量,如何表示
System.out.println(“num=”+num);//30
System.out.println(“num=”+this.num);//40 20
System.out.println(“num=”+OuterClass.this.num);//10

6.如何创建内部类对象

  • import com.bjsxt.oop.innerclass2.OuterClass.InnerClass;
  • OuterClass oc2 = new OuterClass();
    InnerClass ic = oc2.new InnerClass();
    OuterClass.InnerClass ic = new OuterClass().new InnerClass();

7.内部类的分类(了解即可)

  • 1.成员内部类(*****)
  • 2.静态内部类(用的不多)
  • 3.方法内部类(用的不多)
  • 4.匿名内部类(*****)

示例:
/**
*1. 类的成员

  • 成员变量

  • 成员方法

  • 构造方法

  • 静态代码块

  • 代码块

  • 内部类
    *2.内部类

  • 1.内部类是类的成员,所以可以是使用四个权限修饰符进行修饰

  • 2.内部类方法可以直接访问外部类的成员变量和方法

  • 3.外部类方法中不能直接访问内部类的属性和方法,可以间接访问(先创建内部类对象)
    *3.内部类的作用

  • 1.可以定义比private权限更小的作用范围

  • 2.通过内部类可以实现多重继承
    */
    public class OuterClass{
    //成员变量
    private String name;

    //构造方法
    public OuterClass() {
    super();
    }
    public OuterClass(String name) {
    super();
    this.name = name;
    }
    //成员方法
    public void showInfo(){
    System.out.println(“name=”+name);
    }
    public void execInnerClass(){
    System.out.println("--------execInnerClass--------");
    //show();
    //System.out.println(num);
    InnerClass ic = new InnerClass(40);
    System.out.println(ic.num);
    ic.show();
    }
    //静态代码块
    static{
    System.out.println("-----{ }------");
    }
    //内部类
    private class InnerClass{
    //成员变量
    private int num;
    //构造方法
    public InnerClass() {
    super();
    }
    public InnerClass(int num) {
    super();
    this.num = num;
    }
    //成员方法
    public void show(){
    System.out.println(“num=”+num);
    System.out.println(“name=”+name);
    }
    }
    }
    public class Test {
    public static void main(String[] args) {
    OuterClass oc = new OuterClass(“abc”);
    oc.showInfo();
    oc.execInnerClass();
    // OuterClass oc2 = new OuterClass(“cba”);
    // oc2.showInfo();
    }
    }
    public class OuterClass{
    //成员变量
    private String name;
    private int num = 10;
    //构造方法
    public OuterClass() {
    super();
    }
    public OuterClass(String name) {
    super();
    this.name = name;
    }
    //成员方法
    public void showInfo(){
    System.out.println(“name=”+name);
    }
    public void execInnerClass(){
    System.out.println("--------execInnerClass--------");
    //show();
    //System.out.println(num);
    InnerClass ic = new InnerClass();
    System.out.println(ic.num);
    ic.show();

    }
    //静态代码块
    static{
    System.out.println("-----{ }------");
    }
    //内部类
    public class InnerClass {
    //成员变量
    private int num = 20;

    //构造方法
    public InnerClass() {
    	super();
    }
    public InnerClass(int num) {
    	super();
    	this.num = num;
    }
    
    //成员方法
    public void show(){
    	int num = 30;
    	System.out.println("num="+num);//30
    	System.out.println("num="+this.num);//40 20
    	System.out.println("num="+OuterClass.this.num);//10
    	
    	//System.out.println("name="+name);
    }		
    

    }
    }
    public class Test {
    public static void main(String[] args) {
    // OuterClass oc = new OuterClass(“abc”);
    // oc.showInfo();
    // oc.execInnerClass();
    // OuterClass oc2 = new OuterClass(“cba”);
    // oc2.showInfo();
    //InnerClass ic = new InnerClass();
    // OuterClass oc2 = new OuterClass();
    // OuterClass.InnerClass ic = oc2.new InnerClass();
    InnerClass ic = new OuterClass().new InnerClass();
    ic.show();
    }
    }

2.42、匿名内部类
1、匿名内部类的使用场合

  • 如果某些类只使用一次,就没有必要定义一个专门的类,此时使用匿名内部类即可
  • 哪些类只使用一次???
  • 图形界面编程(比如Android)采用事件驱动机制,如果点击了一个按钮,或者一个菜单项,就会触发一个事件,
  • 需要编写事件监听器,对该事件进行处理。
  • 有统一的事件监听器接口,只要实现该接口,重写其方法即可。
  • 问题是每个事件的处理代码一般是不重用,即只用一次。
  • 如果每个操作都创建一个类,类 too many
  • 此时采用 匿名内部类 最好

2、匿名内部类的使用

  • Product p2 = new Product(){
    @Override
    public int getPrice() {
    return 5000;
    }
    @Override
    public String getName() {
    return “apple6plus”;
    }
    };
    showProduct(p2);

3、匿名内部类如何访问外部类的变量

  • 需要将外部类的变量使用final修饰
  • jdk1.8之后final可以不写

示例:
public interface Product {
public abstract double getPrice();
String getName();
}
public class Product1 implements Product{
@Override
public double getPrice() {
return 5000;
}
@Override
public String getName() {
return “thinkpad x200”;
}
}
public class Test {
public static void main(String[] args) {
Product p1 = new Product1();
showProduct(p1);
// System.out.println(p1.getName()+" “+p1.getPrice());
// Product p2 = new Product1();
// System.out.println(p2.getName()+” “+p2.getPrice());
// Product p3 = new Product1();
// System.out.println(p3.getName()+” “+p3.getPrice());
// Product p4 = new Product1();
// System.out.println(p4.getName()+” "+p4.getPrice());

	final double discount=0.8;
	
	Product p2 = new Product(){
		@Override
		public double getPrice() {				
			return 5000*discount;
		}
		@Override
		public String getName() {
			return "apple6plus";
		}			
	};
	showProduct(p2);

	showProduct(new Product(){
		@Override
		public double getPrice() {				
			return 50;
		}
		@Override
		public String getName() {				
			return "Java宝典";
		}			
	});
}

public static void  showProduct(Product p){
	System.out.println(p.getName()+"  "+p.getPrice());
}

}

2.43、垃圾回收机制
讲解要点:
先PPT,介绍概念
代码演示:

System.gc();
Runtime.getRuntime().gc();

总结:
*垃圾回收机制 只回收JVM 堆内存 里的对象空间。(栈、堆、方法区)
*对其他物理连接,比如数据库连接、输入流输出流、Socket连接无能为力

*现在的JVM有多种垃圾回收实现算法,表现各异。

*垃圾回收机制回收任何对象之前,总会先调用它的finalize方法(如果覆盖该方法,让一个新的引用变量重新引用该对象,则会重新激活对象)。(举例子)
*永远不要主动调用某个对象的finalize方法,应该交给垃圾回收机制调用。

*垃圾回收发生具有不可预知性,程序无法精确控制垃圾回收机制执行。
*可以将对象的引用变量设置为null,暗示垃圾回收机制可以回收该对象。
*程序员可以通过System.gc()或者Runtime.getRuntime().gc()来通知系统进行垃圾回收,会有一些效果,但是系统是否立马进行垃圾回收依然不确定。

知识点扩展:
final、finalize、finally的区别?

示例代码:
public class Animal {
@Override
protected void finalize() throws Throwable {
System.out.println(“gc”);
}
}
public class Test {
public static void main(String[] args) {
new Animal();
new Animal();
new Animal();
new Animal();
new Animal();

	//System.gc();
	Runtime.getRuntime().gc();
}

}

综合案例:

MVC
三层架构思想一个体现
三层架构
B/S browse \ Server
V View 视图层 html jsp 控制台
M Model 模型层 封装数据+业务处理
entity javaBean
Service

C Controller 控制器层

标准的JavaBean

  • (1)成员属性私有化
  • (2)提供公共的set\get方法
  • (3)必须要有无参的构造方法
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值