文章目录

  • 05 Java面向对象编程
    • 1. 面向过程与面向对象比较
    • 2. 类和对象
      • 2.1 对象的属性和方法
      • 2.2 类的属性和方法
      • 2.3 定义一个类
      • 2.4 创建和使用对象
      • 2.5 对象和类的总结
      • 2.6 类和对象的课后作业
    • 3. 局部变量和成员变量
    • 4.引用类型
    • 5. 内存分析
    • 6. 构造方法
      • 6.1 重载
    • 7. 构造器
    • 8. 方法调用
    • 9. This关键字
    • 10. Static关键字
      • 10.1 static修饰与非static修饰的区别
    • 11. 代码块
    • 12. Package(包)
      • 12.1 JDK中主要的包
    • 13. Import关键字
      • 13.1 import static(静态导包)
    • 14.面向征对象的三大特征
      • 14.1 封装
        • 14.1.1 使用访问控制符,实现封装
        • 14.1.2 封装要点
      • 14.2 继承
        • 14.2.1 如何使用继承
        • 14.2.2 super关键字
        • 14.2.3 理解继承
        • 14.2.4 继承小结
        • 14.2.5 方法重写
        • 14.2.6 抽象类
        • 14.2.7 final用法
        • 14.2.8 Object类
        • 14.2.9 上机练习
      • 14.3 多态
        • 14.3.1 如何实现多态
        • 14.3.2 计算一次租赁多辆汽车的总租金
        • 14.3.3 多态小结
    • 15.面向接口(interface)编程
      • 15.1 上机练习
        • 15.1.1 使用接口实现防盗门功能
        • 15.1.2 使用接口实现手机功能
        • 15.1.3 组装一台计算机
      • 15.2 interface中的常见错误
      • 15.3 接口总结
    • 16. 内部类
    • 17. 垃圾回收机制

传送门

  • 1.JAVA前瞻
  • 2.JAVA数据类型与运算符
  • 3.Java流程控制语句
  • 4.Java数组
  • 5.Java面向对象编程
  • 6.JAVASE 异常和常用类
  • 7.JAVA容器

05 Java面向对象编程

1. 面向过程与面向对象比较

2. 类和对象

  世界由对象组成;类可以生成对象,类是对象的抽象。类是对象的抽象,对象是类的实例化先有具体的对象,然后抽象各个对象之间象的部分,归纳出类通过类再认识其他对象

2.1 对象的属性和方法

  对象是用来描述客观事物的一个实体,由一组属性和方法构成。

  • 对象的属性:对象具有的各种特征
    每个对象的每个属性都拥有特定值
  • 对象的方法:对象执行的操作
    Java中只有方法概念没有函数概念!

2.2 类的属性和方法

  • 类的属性(成员变量)
    属性用于定义该类或该类对象包含的数据或者说静态属性。属性作用范围是整个类体。在定义成员变量时可以对其初始化,如果不对其初始化,Java使用默认的值对其初始化。
    属性定义格式:

    [修饰符] 属性类型 属性名 = [默认值]
    
    • 修饰符可以省略,可以是:public, protected, private,Static,final
    • 属性类型可以是任何类型,包括基本类型和引用类型
    • 属性名:合法标识符即可。首字母小写,驼峰原则
  • 类的方法
    面向对象中,整个程序的基本单位是类,方法是从属于对象的。方法定义格式:

    [修饰符] 方法返回值类型 方法名(形参列表){//n条语句
    }
    

    JAVA中方法参数传递是值传递

2.3 定义一个类

  定义一个类的步骤:

  1. 定义类名
  2. 编写类的属性
  3. 编写类的方法
/*
* 所有类定义的时候可以添加属性和方法,但是不是必须要写的。
* 一个java文件中可以定义N个class,但是只能有一个public class
* 属性:[修饰符] 属性类型 属性名 = [默认值]
* 方法:[修饰符] 方法返回值类型 方法名(形参列表){//n条语句
}
* 注意:
*      1.方法的访问修饰符可以不写
*      2.方法可以有返回值,也可以没有,void表示没有返回值的意思
*      3.形参列表可以有,也可以没有
*/public class Student {//定义类属性int stuNumber;String name;int age = 20;//定义类方法void study(){System.out.println("我正在学习");}void eat(String food){System.out.println("我正在吃"+food);}
}

2.4 创建和使用对象

  • 创建对象:使用new关键字来创建

    类名 对象名 = new 类名();
    
  • 使用对象成员:使用“.”进行以下操作
    • 引用类的属性:对象名.属性
    • 引用类的方法:对象名.方法名()
public class Student {//定义类属性int stuNumber;String name;int age = 20;//定义类方法void study(){System.out.println("我正在学习");}void eat(String food){System.out.println("我正在吃"+food);}public static void main(String[] args) {//创建对象Student student = new Student();//使用属性System.out.println(student.name);System.out.println(student.age);System.out.println(student.stuNumber);//使用方法student.study();student.eat("苹果");}
}
null
20
0
我正在学习
我正在吃苹果

2.5 对象和类的总结

  • 对象和类的关系:特殊到一般,具体到抽象。
  • 类:我们叫做class。对象:我们叫做Object instance(实例)。以后我们说某个类的对象,某个类的实例。是一样的意思。
  • 类可以看成一类对象的模板,对象可以看成该类的一个具体实例。
  • 类是用于描述同一类形的对象的一个抽象的概念,类中定义了这一类对象所应具有的静态和动态属性。
  • 对象是Java程序的核心,在Java程序中“万事万物皆对象"。
  • JDK提供了很多类供编程人员使用,编程人员也可定义自己的类。

2.6 类和对象的课后作业

  1. 定义管理员类

    实现思路:

    • 定义管理员类Administrator
    • 定义其属性和方法
    • 定义测试类TestAdministrator
    • 创建两个管理员类的对象,并输出他们的信息
    /*
    * 创建管理员对象
    * */
    import java.util.Scanner;public class Administrator {String loginName = "admin";//用户名String password = "123456";//密码public void introduce() {System.out.println(loginName);System.out.println(password);}public static void main(String[] args) {//创建对象Administrator admin = new Administrator();admin.introduce();}
    }
    
  2. 更改管理员密码

    需求说明:

    • 输入旧的用户名和密码,如果正确,方有权限更新
    • 从键盘获取新的密码,进行更新

    实现思路:

    • 创建管理员类的对象
    • 利用while实现循环执行
    /*
    * 创建管理员对象
    * */
    import java.util.Scanner;public class Administrator {String loginName = "admin";//用户名String password = "123456";//密码public void introduce() {System.out.println(loginName);System.out.println(password);}//输入旧的用户名和密码,如果正确,方有权限更新//从键盘获取新的密码,进行更新public static void main(String[] args) {//创建对象Administrator admin = new Administrator();//从控制台读取数据Scanner sc = new Scanner(System.in);System.out.println("修改密码");while (true){System.out.println("请输入用户名称:");String name = sc.nextLine();System.out.println("请输入密码:");String pwd = sc.nextLine();//如果密码正确,才有权限更新新密码//字符串在比较的时候使用equal,不使用==;==比较的是内存地址if (name.equals(admin.loginName)  && pwd.equals(admin.password)){admin.loginName = sc.nextLine();admin.password = sc.nextLine();break;}else{System.out.println("用户名和密码不正确,请重新输入!");}}}
    }
    

3. 局部变量和成员变量

区别:

  • 声明位置不同
    成员变量在类中,局部变量在方法中
  • 作用范围不同
    成员变量作用在当前类方法中,局部变量作用在当前方法中(不同方法中即使有同名的局部变量,没有关系,互不影响,建议相同)
  • 内存存放位置不同
    局部变量存放在栈内存中,成员变量存放在堆内存中
  • 成员变量有默认值;局部变量没有默认值
/*
* 变量:
*   局部变量:定义在方法中的变量,称为局部变量
*       - 作用域:从定义位置开始到整个方法结束
*       - 局部变量只能在当前方法中使用,其他方法无法使用
*       - 局部变量不包含默认值,如果没有使用当前变量的话,可以不赋值
*   成员变量:定义在类中的变量称为成员变量(全局变量)
*       - 作用域:当前类方法中
*       - 成员变量包含初始值 int 0   String null    bollean false
* */
public class VarDemo {// 成员变量static int age = 20;public void test(){System.out.println("2-----------"+age);age = 10; //成员变量重新赋值System.out.println("3-----------"+age);//局部变量int age = 30;System.out.println("4-----------"+age);}public void show(){//局部变量int a = 10;String name = "liujie";}public static void main(String[] args) {System.out.println("1-----------"+age);
//        System.out.println(a);  //局部变量的作用域只在当前方法中new VarDemo().test();System.out.println("5-----------"+age);  //这里打印出来是10}
}
1-----------20
2-----------20
3-----------10
4-----------30
5-----------10

4.引用类型

  Java语言中除基本类型之外的变量类型都称之为引用类型。

Java中的对象和数组是通过引用对其操作的。

  • 引用可以理解为一种受限的指针
  • 指针是可以进行与整数做加减运算的,两个指针之间也可以进行大小比较运算和相减运算。引用不行,只能进行赋值运算。
  • 引用就是一个变量或对象的别名(引用的本质是一个对象);指针是一个段内存空间的地址(指向存储一个变量值的空间或一个对象的空间)。

    引用只能保存对应的地址,通过地址找到内存空间里的值。

5. 内存分析

  • (FILO)

    • 存放:局部变量
    • 后进先出,自下而上存储
    • 方法执行完毕,自动释放空间
    • 存放:new出来的对象
    • 需要垃圾回收器来回收:System.gc()
  • 方法区

    • 存放:类的信息(代码)、static变量、字符串常量等
public class Student {//定义类属性int stuNumber;String name;int age = 20;//定义类方法void study(){System.out.println("我正在学习");}void eat(String food){System.out.println("我正在吃"+food);}public static void main(String[] args) {//创建对象Student student = new Student();//使用属性System.out.println(student.name);System.out.println(student.age);System.out.println(student.stuNumber);//修改属性值,给属性赋值student.name = "张三";student.age = 40;student.stuNumber = 2019210004;//使用属性System.out.println(student.name);System.out.println(student.age);System.out.println(student.stuNumber);//使用方法student.study();student.eat("苹果");}
}

6. 构造方法

  构造方法:创建对象的时候默认会调用构造方法来创建对象,在堆中开辟空间,完成成员变量的某些初始化。

构造方法的语法(特点):

  • 方法名称:构造方法的方法名称必须跟类名称保持一致
  • 访问修饰符:
  • 形参:可以用户自定义添加,跟方法的普通参数一样
  • 方法体:完成对象的初始化功能
  • 返回值:没有返回值

注意:

  1. 创建完类之后,如果没有手动调用构造方法,会有一个默认的无参的构造方法供调用
  2. 当用户自定义了构造方法之后,默认的无参构造方法就不能使用了, 必须手动定义无参构造方法
  3. 同一个类中可以包含多个同名的构造方法
public class Teacher {String name;int age;//构造方法1public Teacher(){}//构造方法2public Teacher(String xname,int xage){System.out.println("two argumnet");name = xname;age = xage;}public void teach(){System.out.println("上课");}public static void main(String[] args) {//构造方法1Teacher teacher = new Teacher();teacher.name = "liujie";teacher.age = 25;System.out.println(teacher.name);System.out.println(teacher.age);//构造方法2Teacher teacher2 = new Teacher("lisi",20);System.out.println(teacher2.name);System.out.println(teacher2.age);Teacher teacher3 = new Teacher("wangwu");System.out.println(teacher3.name);}
}
liujie
18
two argumnet
lisi
20
one argumnet
wangwu

6.1 重载

  在一个类中可以包含多个重名的方法,但是注意方法的参数列表不能相同
三个方面的不同:

  • 参数的个数不同
  • 参数的类型不同
  • 参数的顺序不同

注意:当自定义构造方法后,系统不再默认提供无参构造方法。一般构造方法都会进行重载(一个类中可以包含多个属性值,当只需要给部分属性初始化时需要调用不同的构造方法)。

public class Teacher {String name;int age;//构造方法1public Teacher(){}//构造方法2public Teacher(String xname,int xage){System.out.println("two argumnet");name = xname;age = xage;}//构造方法重载public Teacher(String xname){System.out.println("one argumnet");name = xname;}public void teach(){System.out.println("上课");}public static void main(String[] args) {//构造方法1Teacher teacher = new Teacher();teacher.name = "liujie";teacher.age = 18;System.out.println(teacher.name);System.out.println(teacher.age);//构造方法2Teacher teacher2 = new Teacher("lisi",20);System.out.println(teacher2.name);System.out.println(teacher2.age);Teacher teacher3 = new Teacher("wangwu");System.out.println(teacher3.name);}
}
liujie
18
two argumnet
lisi
20
one argumnet
wangwu

7. 构造器

  构造器定义:constructor构造方法,一个在创建对象时被自动调用的特殊方法。

  • 构造器的作用:为对象进行初始化(成员变量)工作
  • 构造器是一种特殊的方法:
    • 构造器的方法名必须和类名一致!
    • 构造器虽然有返回值,但是不能定义返回类型(返回值的类型肯定是本类),不能在构造器里调用return。
    • 通过new关键字调用!
    • 如果我们没有定义构造器,则系统会自动定义一个无参的构造方法。如果已定义则编译器不会添加无参构造方法
    • 与普通方法一样,构造方法也可以重载

案例

  定义一个“点”(Point)类用来表示二维空间中的点(有二个坐标)。要求如下:

  • 可以生成具有特定坐标的点对象。
  • 提供可以设置二个坐标的方法。
  • 提供可以计算该"点"距另外点距离的方法。
  • 代码实现交换point中两个坐标的值(实现用对象作为参数)
public class Point {int x;int y;//设置二维坐标点public void set(int xx, int yy) {x = xx;y = yy;}// 计算该“点“距另外点的距离public double caclcDistance(Point p) {return Math.sqrt((p.x - x) * (p.x - x) + (p.y - y) * (p.y - y));}//交换point中两个坐标的值(实现用对象作为参数)public void changePoint(Point p){int a = p.x;p.x = x;x = a;int b = p.y;p.y = y;y = b;}//打印坐标点public void show(){System.out.println("["+x+","+y+"]");}//主函数public static void main(String[] args) {//设置第一个点Point p1 = new Point();p1.set(3,5);//设置第二个点Point p2 = new Point();p2.set(2,4);//计算两点之间的距离System.out.print("计算两点之间的距离:");System.out.println(p1.caclcDistance(p2));//交换第一个点与第二个点的值,并打印p1.changePoint(p2);p1.show();p2.show();}
}
计算两点之间的距离:1.4142135623730951
[2,4]
[3,5]

8. 方法调用

  • 形参和实参

    • 定义方法的参数是形式参数
    • 调用方法的参数是实在参数
    • 调用方法时要求参数个数相同,类型兼容
  • 参数传递
    • 基本数据类型的参数传递:无法通过方法调用改变变量的值
    • 引用数据类型的参数传递:可以通过方法调用改变变量的值

基本数据类型的参数传递:无法通过方法调用改变变量的值

package com.mashibing;
/*
* 方法参数的值是否改变
*   方法中的参数列表叫做形式列表,没有具体的值,只是为了方便在方法体中使用
*   调用方法的时候实际传入的值叫做实参,代表具体的数值,用来替换在方法体中代码逻辑的值进行运算
*   注意:
*       1.形式参数的变量名称也是局部变量
*       2.基本数据类型的参数传递:不能改变参数的值
* */
public class ArgumentDemo {public static void test(int a,int b){int tmp = a;a = b;b = tmp;}public static void main(String[] args) {int a = 10;int b = 20;test(a,b);System.out.println(a);System.out.println(b);}
}
10
20

引用数据类型的参数传递:可以通过方法调用改变变量的值
Point.java

package com.mashibing;public class Point {private int x;private int y;public Point(int x,int y) {this.x = x;this.y = y;}public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}
}

ArgumentDemo.java

package com.mashibing;
/*
* 方法参数的值是否改变
*   方法中的参数列表叫做形式列表,没有具体的值,只是为了方便在方法体中使用
*   调用方法的时候实际传入的值叫做实参,代表具体的数值,用来替换在方法体中代码逻辑的值进行运算
*   注意:
*       1.形式参数的变量名称也是局部变量
*       2.基本数据类型的参数传递:不能改变参数的值
*   java中的参数传递是值传递
* */
public class ArgumentDemo {public static void test(Point point){int x = point.getX();int y = point.getY();int tmp = x;x = y;y = tmp;point.setX(x);point.setY(y);}public static void main(String[] args) {Point point = new Point(2,3);test(point);System.out.println(point.getX());System.out.println(point.getY());}
}
3
2

9. This关键字

  this表示的是当前对象本身,this代表当前对象的一个引用。

  • 普通方法中使用this

    • 区分成员属性和方法的形参
    • 调用当前对象的其他方法(可以省略)
    • 位置:任意
  • 构造方法中使用this
    • 当构造方法中的参数名称跟类的成员变量一样的时候,可以使用this代表当前对象。有了this后可以将构造方法的参数跟成员变量的保持一致
    • 当构造方法中需要调用其他的构造方法时,可以使用this()(这个括号相当this.ThisDemo())调用其他构造方法,但是必须位于构造方法第一行

this不能用于static方法。

/*
* this关键字:表示当前对象的指针
* 用处:
*   1.构造方法:当构造方法中的参数名称跟类的成员变量一样的时候,可以使用this代表当前对象
*       有了this后可以将构造方法的参数跟成员变量的保持一致
*       当构造方法中需要调用其他的构造方法时,可以使用this()(这个括号相当于this.ThisDemo())调用其他构造方法,
*       但是必须位于构造方法第一行
*   2.普通方法:当多个普通方法之间需要调用时,可以使用this进行调用,指的是当前对象的其他方法
*   3.成员变量的使用:当方法中的参数名称跟成员变量保持一致的时候,使用this表示的是对象的值
*     使用变量名称表示的是形参的值
*   4.只要在当前类中定义的this都表示同一个this
* */
public class ThisDemo {String name;int age;//构造方法:当构造方法中的参数名称跟类的成员变量一样的时候,可以使用this代表当前对象public ThisDemo(String name,int age){this.name = name;this.age = age;}//当多个普通方法之间需要调用时,可以使用this进行调用,指的是当前对象的其他方法public void test1(){System.out.println("test1");}public void test2(String name){System.out.println("test2");this.test1(); //this可以省略//使用this表示的是对象的值,使用变量名称表示的是形参的值//这两个值不一样,name是lisi,this.name是zhangsanSystem.out.println(name);System.out.println(this.name);}public static void main(String[] args) {ThisDemo ts = new ThisDemo("zhangsan",25);System.out.println(ts.name);System.out.println(ts.age);ts.test2("lisi");}
}
zhangsan
25
test2
test1
lisi
zhangsan

10. Static关键字

  在类中,用static声明的成员变量为静态成员变量,或者叫做:类属性,类变量。

它为该类的公共变量,属于类,被该类的所有实例共享,在类被载入时被显式初始化,对于该类的所有对象来说,static成员变量只有一份。被该类的所有对象共享!!可以使用"对象.类属性"来调用。不过,一般都是用“类名.类属性”。

static变量置于方法区中!

用static声明的方法为静态方法,不需要对象

  • 不需要对象,就可以调用(类名.方法名)

  • 在调用该方法时,不会将对象的引用传递给它,所以在static方法中不可访问非static的成员。

  • 静态方法中不能直接调用非静态方法,可以先创建对象在进行非静态方法的调用

  • 静态方法不能以任何方式引用this和super关键字(因为static在对象创建之前就已经存在)

下面的两个注意,尤为重要!!!

/**ststic:*  修饰成员变量的时候,表示静态成员变量或者类变量*       普通变量在使用的时候,必须要通过对象名进行调用*       类变量可以使用对象名调用也可以使用类名进行调用**  注意:*      - 静态变量,在创建对象之前被初始化,或者说在类被载入之前进行初始化*      - 静态变量被所有对象共享,属于公共变量,对象和列都可以直接调用,但是推荐使用类来调用*      - 成员变量放在堆中,而静态变量放在方法区中静态区*      - 静态变量是不能定义在方法中的**  修饰方法的时候,表示静态方法或者叫类方法*      - 普通方法在使用的时候,必须通过对象名调用*      - 类方法或者静态方法可以使用类名调用也可以使用对象名调用*  注意:*      - 静态方法可以在非静态方法中进行调用*      - 静态方法中不能直接调用非静态方法,可以先创建对象在进行非静态方法的调用*      - 静态方法中不允许出现this调用*      - 一般工具类中的方法定义为static* */public class StaticDemo {String name = "zhangsan";static int age = 10;//静态方法public static void test() {System.out.println("static");}//非静态方法,在普通方法中调用静态方法public void test2() {test();}public static void main(String[] args) {StaticDemo staticDemo = new StaticDemo();//使用对象进行调用System.out.println(staticDemo.name);System.out.println(staticDemo.age); //10staticDemo.age = 20;System.out.println(staticDemo.age); //20System.out.println(StaticDemo.age); //20StaticDemo.age = 30;System.out.println(staticDemo.age); //30System.out.println(StaticDemo.age); //30StaticDemo staticDemo1 = new StaticDemo();System.out.println(staticDemo1.age); //30System.out.println(StaticDemo.age);  //30//使用类名进行调用//System.out.println(StaticDemo.name); //name不能打印,因为name归属于当前对象System.out.println(StaticDemo.age); //30//静态方法或者类方法的调用StaticDemo staticDemo2 = new StaticDemo();staticDemo2.test();staticDemo2.test2();StaticDemo.test();}
}
  • 静态属性的访问形式

    • 对象名.属性
    • 类名.属性----------推荐
  • 静态方法的访问形式

    • 对象名.方法名()
    • 类名.方法名()---------推荐

10.1 static修饰与非static修饰的区别

11. 代码块

  使用”{}”括起来的一段代码。根据位置可分类:

  • 普通代码块:定义在方法中或语句中定义的代码块

  • 构造代码块:定义在类中的代码块

    • 每次代码运行的时候会将构造代码块中的代码添加到构造方法的前面
    • 构造代码块中的代码会添加到每一个构造方法中,当使用this(参数)的时候不会添加
  • 静态代码块:使用static声明的代码块,在程序载入的时候优先执行

    • 如果希望加载后,对整个类进行某些初始化操作,可以使用static初始化块。
    • 类第一次被载入时先执行static代码块;类多次载入时,static代码块只执行一次;Static经常用来进行static变量的初始化。
    • 静态代码块是在类初始化时执行,不是在创建对象时执行
    • 静态代码块中不能访问非static成员
    • 数据库连接等其他提前需要准备好的代码会放在static代码块中
  • 同步代码块:多线程的时候会使用,用来给共享空间进行加锁操作

执行顺序:静态代码块 => 构造代码块(创建对象的时候才会用到)=> 普通代码块

/*
*- 普通代码块:定义在方法中或语句中定义的代码块
*- 构造代码块:定义在类中的代码块
*   注意:
*   - 每次代码运行的时候会将构造代码块中的代码添加到构造方法的前面
*   - 构造代码块中的代码会添加到每一个构造方法中,当使用this(参数)的时候不会添加
*- 静态代码块:使用static声明的代码块,在程序载入的时候优先执行,就算不创建对象也会优先执行
*   - 数据库连接等其他提前需要准备好的代码会放在static代码块中
*- 同步代码块:多线程的时候会使用,用来给共享空间进行加锁操作
* */public class CodeBlockDemo {int a;int b;//静态代码块static {System.out.println("静态代码块");}//构造代码块,反编译时会默认将这句话加入每一个构造方法中{System.out.println("构造代码块");}//构造方法1public CodeBlockDemo() {System.out.println("构造方法");}//构造方法2public CodeBlockDemo(int a) {this.a = a;}//构造方法3public CodeBlockDemo(int a,int b) {this(a);this.b = b;}public void test(){System.out.println("test");{System.out.println("我应该是什么分类");}}public static void main(String[] args) {//构造方法1CodeBlockDemo codeBlockDemo = new CodeBlockDemo();codeBlockDemo.test();//构造方法2CodeBlockDemo codeBlockDemo1 = new CodeBlockDemo(2);System.out.println(codeBlockDemo1.a);// 普通代码块{System.out.println("main");}}
}
静态代码块
构造代码块
构造方法
test
我应该是什么分类
构造代码块
2
main

12. Package(包)

  为什么需要Package?

  • 为了解决类之间的重名问题
  • 为了便于管理类,合适的类位于合适的包

Package怎么用?

  • 通常是类的第一句非注释性语句
  • 包名:域名倒着写即可,再加上模块名,并与内部管理类

注意事项:

  • 写项目时都要加包,不要使用默认包
  • com.gao和com.gao.car,这两个包没有包含关系,是两个完全独立的包。只是逻辑上看起来后者是前者的一部分
package com.mashibing;/*
* package:包,对应到文件系统就是多级目录
* 使用:一般定义package会放置在java文件的第一行
* 语法:package 域名的倒写
*   package com.com.mashibing
* 完全限定名:包名+类名
* */
public class PackageDemo {}

12.1 JDK中主要的包

  • java.lang(不需要手动导入,自动加载)

    包含一些Java语言的核心类,如String、Math、Integer、System和Thread,提供常用功能。

  • java.awt

    包含了构成抽象窗口工具集(abstract window toolkits)的多个类,这些类被用来构建和管理应用程序的图形用户界面(GUI)

  • java.net(网络包)

    包含执行网络相关的操作的类。

  • java.io(输入输出流包)

    包含能提供多种输入/输出功能的类

  • java.util(工具包)
    包含一些实用工具类,如定义系统特性、使用与日期日历相关的函数

13. Import关键字

  为什么需要import?

当需要引入非lang包的其他java类的时候,需要使用import工具。如果不使用import,我们如果用到其他包的类时,只能这么写:java.util.Date,代码量太大,不利于编写和维护。通过import可以导入其他包下面的类,从而可以在本类中直接通过类名来调用。

import怎么使用?import java.包名.类名

import java.util.Date;  //导入具体的类
import java.util.*   ///导入该包下所有的类,会降低编译速度,但不会降低运行速度。

注意:

  • java会默认导入java.lang包下所有的类,因此这些类我们可以直接使用。

  • 如果导入两个同名的类,只能用包名+类名来显示调用相关类

    当一个java文件中需要使用多个同名的类的时候,只能选择导入一个,另一个使用完全限定名的方式进行导入

13.1 import static(静态导包)

  当需要使用某个类的多个方法的时候,同时又不想频繁写该类的名称,此时可以使用静态导包

静态导入的作用:用于导入指定类的静态属性

package com.mashibing;import static java.lang.Math.*; //导入Math类的所有静态属性public class ImportDemo {public static void main(String[] args) {System.out.println(Math.sqrt(4));System.out.println(sqrt(4));System.out.println(Math.abs(-4));System.out.println(abs(-4));}
}

14.面向征对象的三大特征

14.1 封装

  封装的概念:将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。

封装的好处

  • 只能通过规定的方法访问数据
  • 隐藏类的内部实现细节
  • 方便加入控制语句
  • 方便修改实现

封装可以隐藏对象内部的复杂性,只对外公开简单的接口,便于外界调用,从而提高系统的可扩展性、可维护性。程序设计要追求高内聚,低耦合

  • 高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;
  • 低耦合就是仅暴露少量的方法给外部使用

如何使用封装

  1. 修改属性的可见性:设为private
  2. 创建共有的getter/setter方法:用于属性的读写
  3. 在getter/setter方法中加入属性控制语句:对属性值的合法性进行判断

案例

Dog.java

package com.mashibing;
/*
* 定义类的时候需要包含以下组件:
*   - 私有属性
*   - 构造方法(无参构造方法与自定义构造方法)
*   - set/get方法,可以在里面添加逻辑判断
*   - 普通方法
* */
public class Dog {private String name;//private:将类的某些信息隐藏在类的内部,不允许外部程序直接访问private int age;private String color;//无参构造方法public Dog() {}//构造方法public Dog(String name, int age, String color) {this.name = name;this.age = age;this.color = color;}//提供设置年龄的方法,外部程序通过访问这个方法实现对隐藏信息的操作和访问,public void setAge(int age) {if (age > 0) {this.age = age;} else {System.out.println("输入年龄不规范,重新输入");}}//提供获取年龄的接口public int getAge() {return this.age;}//提供设置名字的接口public void setName(String name) {this.name = name;}//提供获取名字的接口public String getName() {return this.name;}//提供设置颜色的接口public void setColor(String color) {this.color = color;}//提供获取颜色的接口public String getColor() {return this.color;}public void eat() {System.out.println("吃骨头");}public void play() {System.out.println("playing");}//展示public void show() {System.out.println("name:" + this.name);System.out.println("age:" + this.age);System.out.println("color:" + this.color);}}

DogTest.java

package com.mashibing;
/*
* 封装可以解决什么问题?
*   如果任何一个处理类都可以直接对Dog进行赋值操作,那么当值不准确的时候,会产生额外错误
*   如果在赋值的同时添加一些逻辑判断呢?
*       封装可以解决此问题
* 封装的作用:
*   使用封装可以保证数据的规范,不符合规范的数据将无法进行操作
* 封装的好处:
*   - 只能通过规定的方法访问数据
*   - 隐藏类的内部实现细节
*   - 方便加入控制语句
*   - 方便修改实现
* 面向对象的封装概述:(狭义的封装)
*   将类中的属性设置为私有属性,提供共有的外部方法供程序进行调用,可以实现丰富的细节操作
* 广义的封装:
*   可以将完成特定功能的代码块封装成同一个方法,供不同程序进行调用
* */
public class DogTest {public static void main(String[] args) {Dog dog = new Dog();dog.setName("大黄");
//        dog.setAge(-20);dog.setAge(7);dog.setColor("yellow");dog.show();}
}

14.1.1 使用访问控制符,实现封装

成员(成员变量或成员方法)的访问权限共有四种:(按照从大到小的顺序排列)

  • public(公共的)

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

  • protected(受保护的)

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

  • default/friendly (默认权限(包可见性))

    被这个类本身访问;被同一个包中的类访问

  • private(私有的)

    只能被这个类本身访问(类可见性)

类的访问权限只有两种:

  • public(公共的)

    可被同一项目中的所有类访问(必须与文件名同名)

  • default/friendly (默认的/友好的)

    可被同一个包中的类访问。

14.1.2 封装要点

  • 类的属性处理:

    • 一般使用private(除非本属性确定会让子类继承)
    • 提供相应的get/set方法来访问相关属性,这些方法通常是public,从而提供对属性的读取操作(注意:boolean变量的get方法是用is开头)
  • 一些只用于本类的辅助性方法可以用private,希望其他类的调用方法用public

14.2 继承

  类是对对象的抽象,继承是对某一批类的抽象,从而实现对现实世界更好的建模,提高代码的复用性。使用继承优化设计,将重复代码抽取到父类中。使用继承优化后:子类与父类是is-a的关系,方便修改代码,减少代码量。

  1. 使用继承的时候需要使用extend关键字
  2. 使用继承关系之后,父类中属性和方法都可以在子类中调用(非私有属性和非私有方法)
  3. Java是单继承的(如果包含多个父类,同时父类中包含重名方法,无法决定调用谁)

代码未优化前:
Dog.java:

package com.mashibing.extend;public class Dog {//定义私有属性private String name;private int age;private String gender;private String sound;//无参构造方法public Dog(){}//有参构造方法public Dog(String name, int age, String gender, String sound) {this.name = name;this.age = age;this.gender = gender;this.sound = sound;}//get set方法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 getSound() {return sound;}public void setSound(String sound) {this.sound = sound;}
}

Penguin.java:

package com.mashibing.extend;public class Penguin {// 私有属性private String name;private int age;private String gender;private String color;//无参构造方法public Penguin(){}//有参构造方法public Penguin(String name, int age, String gender, String color) {this.name = name;this.age = age;this.gender = gender;this.color = color;}//get set方法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 getColor() {return color;}public void setColor(String color) {this.color = color;}
}

使用继承优化之后:
Pet.java:

package com.mashibing.extend;public class Pet {//私有属性private String name;private int age;private String gender;//无参构造方法public Pet(){}//有参构造方法public Pet(String name, int age, String gender) {this.name = name;this.age = age;this.gender = gender;}//get set 方法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;}
}

Dog.java:Dog类继承Pet类

package com.mashibing.extend;public class Dog extends Pet{//定义私有属性private String sound;//无参构造方法public Dog(){}//有参构造方法public Dog(String name, int age, String gender, String sound) {super(name,age,gender);this.sound = sound;}//get set方法public String getSound() {return sound;}public void setSound(String sound) {this.sound = sound;}
}

Penguin.java:Penguin类继承Pet类

package com.mashibing.extend;public class Penguin extends Pet{// 私有属性private String color;//无参构造方法public Penguin(){}//有参构造方法public Penguin(String name, int age, String gender, String color) {super(name,age,gender);this.color = color;}//get set方法public String getColor() {return color;}public void setColor(String color) {this.color = color;}
}

Test.java

package com.mashibing.extend;/*
* 继承:
*   表示父类与子类之间的关系,
*   当两个类或者多个类具备多个相同的属性和方法的时候,可以提取出来变成父类,子类可以继承
*   子类和父类是is-a关系
*
* 使用:
*   1.使用继承的时候需要使用extend关键字
*   2.使用继承关系之后,父类中属性和方法都可以在子类中调用(非私有属性和非私有方法)
*   3.Java中是单继承的(如果包含多个父类,同时父类中包含重名方法,无法决定调用谁)
* */
public class PetTest {public static void main(String[] args) {//创建dog对象Dog dog = new Dog();//setName、getName方法均不在Dog类中,但是由于使用了继承可以直接使用父类的属性和方法dog.setName("大黄");System.out.println(dog.getName());}}

14.2.1 如何使用继承

  • 编写父类

    public class Pet {//公有的属性和方法
    }
    
  • 编写子类,继承父类

    //只能继承一个父类(单继承)
    public class Penguin extends Pet{}
    

14.2.2 super关键字

  super是直接父类对象的引用,可以通过super来访问父类中被子类覆盖的方法或属性

  • 普通方法:
    没有顺序限制,可以随便调用
  • 构造函数
    在任何类的构造函数中,若是构造函数的第一行代码没有显示的调用super(…),那么Java默认会调用super();作为父类的初始化函数。所以这里的super()加不加都无所谓。
* super是直接父类对象的引用,可能存在多重继承关系,所以要分清
*   用途:
*       1.可以在子类中调用父类中被子类覆盖的方法  ---- super.父类方法名称
*       2.当super在普通方法中使用的话,可以任意位置编写
*       3.当super在构造方法中使用的话,会调用父类的构造方法,一定要将super放在第一行
*       4.在构造方法中super关键字与this关键字(this构造方法调用)不能同时出现
*       5.父类中私有的属性和方法都不能被调用,包括构造方法
*       6.子类的构造方法中都会默认super关键字调用父类的无参构造方法,
*         因此在定义类的时候,无论自己是否自定义了其他构造方法,最好将无参构造方法写上
*       7.如果构造方法中显示的指定了super的构造方法,那么无参的构造方法就不会被调用
*
* 总结:
*   1.在创建子类对象的时候,一定会优先创建父类对象
*   2.所有的java类都具备同一个老祖宗类,称之为Object,是所有类的根类

super关键字来访问父类的成员

  • super只能出现在子类的方法和构造方法中
  • super调用构造方法时,只能是第一句
  • super和this不能同时出现在构造方法中
  • super不能访问父类的private成员
  • super和this都不能在static方法中

父类的静态方法子类可以调用,但是子类不可以重写

14.2.3 理解继承

  子类可以继承父类的所有资源嘛?

不能被继承的父类成员:

  1. 不能直接访问private成员
  2. 子类与父类不在同包,使用默认访问权限的成员
  3. 构造方法(但是可以直接调用父类的构造方法)

  多重继承关系的初始化顺序是怎样的?

在创建子类对象的时候必须优先创建父类对象,初始化顺序为父类属性 —> 父类构造方法 —> 子类属性 —> 子类构造方法。

  继承中构造方法的调用顺序

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

14.2.4 继承小结

  • 通过继承可以简化类的定义,实现代码的重用
  • 子类继承父类的成员变量和成员方法,但是不继承父类的构造方法,可以调用父类的构造方法
  • java中只有单继承,没有像c++那样的多继承。多继承会引起混乱,使得继承链过于复杂,系统难以维护。
  • java中的多继承可以通过接口来实现
  • 如果定义一个类时,没有调用extends,则它的父类是java.lang.Object

14.2.5 方法重写

  方法重写与重载没有任何关系!!!

在子类中可以根据需要对从基类中继承来的方法进行重写;重写方法必须和被重写方法具有相同的方法名称、参数列表和返回类型;重写方法不能使用比被重写方法更严格的访问权限(由于多态)。

Pet.java:

package com.mashibing.extend;public class Pet {//私有属性private String name;private int age;private String gender;//无参构造方法public Pet(){System.out.println("Pet 无参构造方法");}//有参构造方法public Pet(String name, int age, String gender) {this.name = name;this.age = age;this.gender = gender;}//get set 方法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 void play(){System.out.println("play....");}@Overridepublic String toString(){return "my name is"+this.name+",my age is"+this.age+",my gender is"+this.gender;}
}

Dog.java:

package com.mashibing.extend;public class Dog extends Pet{//定义私有属性private String sound;//无参构造方法public Dog(){System.out.println("dog 无参构造方法");}//有参构造方法public Dog(String name, int age, String gender, String sound) {super(name,age,gender);this.sound = sound;}//get set方法public String getSound() {return sound;}public void setSound(String sound) {this.sound = sound;}@Overridepublic void play(){super.play();System.out.println("dog is playing ball");}@Overridepublic String toString(){return super.toString()+",my sound is"+this.sound;}
}

PetTest.java:

package com.mashibing.extend;/*
* 重写:
*   必须存在继承关系,当父类中的方法无法满足子类需求的时候可以选择使用重写的方式
* 注意:
*   1.重写表示子类覆盖父类的方法,当覆盖之后,调用同样的方法的时候会优先调用子类
*   2.重写的方法名称,返回值类型,参数列表必须跟父类一致
*   3.子类重写的方法不允许比父类的方法具备更小的访问权限
*       父类:public    子类:public
*       父类:protected 子类:public,protected
*       父类:default  子类:public,protected,default
*   4.构造方法可以被重写嘛?
*       不能,因为构造方法不能被继承,因此不能被重写
*   5.父类的静态方法子类可以调用,但是子类不可以重写
* */
public class PetTest {public static void main(String[] args) {Pet pet = new Pet();//该类中必须有toString方法才会打印出来其中内容,否则会打印地址System.out.println(pet);Dog dog = new Dog();System.out.println(dog);}
}
Pet 无参构造方法
my name isnull,my age is0,my gender isnull
Pet 无参构造方法
dog 无参构造方法
my name isnull,my age is0,my gender isnull,my sound isnull

14.2.6 抽象类

  在某些情况下,某些类不具备实例化的意义,因此,Java中使用抽象类来限制实例化

/*
* java中的对象是对现实世界的具象化,但是在现实世界中,某些类并不具备实例化的意义,因此,可以定义为抽象类
* 抽象类:
*       1.创建抽象类的时候需要添加abstract关键字
*       2.不能进行实例化,也就是不能new对象
*       3.抽象类中的某些方法没有方法体,需要子类进行更丰富的实现,父类实现没有意义,
*         此时可以将抽象类中的方法定义为抽象方法,
*         只包含方法名称、返回值、参数列表、访问修饰符
*       4.使用abstract关键字修饰的方法叫做抽象方法,抽象方法必须在抽象类里,可以不写方法的实现
*       5.**子类在继承抽象父类的时候,必须要将父类中的抽象方法进行实现除非子类也定义为抽象类**
*       6.有抽象方法的一定是抽象类,但是抽象类中不一定包含抽象方法
* */

案例:抽象Pet类

需求说明:

  • 修改Pet类为抽象类
  • 修改Pet类的print方法为抽象方法
  • 输出Dog信息

Pet.java:

package com.mashibing.abstracts;//抽象类
public abstract class Pet {private String name;private int age;//抽象方法public abstract void print();public void play(){System.out.println("paly...");}}

Dog.java:

package com.mashibing.abstracts;public class Dog extends Pet{private String gender;//在子类中对抽象方法进行具体实现@Overridepublic void print(){System.out.println("dog print");}
}

AbstractTest.java:

package com.mashibing.abstracts;public class AbstractTest {public static void main(String[] args) {Dog dog = new Dog();dog.print();dog.play();}
}
dog print
paly...

14.2.7 final用法

* final的使用:
*   1.final可以装饰变量,表示变量的值不可变,即为常量
*   2.final可以装饰方法,表示方法不可以被重写
*   3.final可以修饰类,表示类不可以被继承

14.2.8 Object类

  Object类是所有类的父类。一个类如果没有使用extends显性的继承另外一个类,那么这个类就继承自Object类。

Object类的方法

  • hashCode方法:计算哈希值,一般自定义实现类时,需要重写hashCode方法
  • equals方法:比较两个对象地址是否相同,一般自定义类时,需要重写equals方法,比较两个属性值是否相同
  • clone方法:创建当前对象的一个副本
  • toString方法:默认返回包名.类名.@哈希码,可以重写
  • notify、notifyAll、wait:表示线程的等待与唤醒,用于多线程
  • finalize方法:判断当前对象是否能够被回收,如果没有引用就会被回收

Object类的主要方法

  1. toString()方法

    public static void main(String [] args){Person p=new Person();//创建Person的对象p;System.out.println("不加toString()的输出:"+p);System.out.println("加上toString()的输出:"+p.toString());
    }
    //加与不加toString的效果相同,都会调用父类Object中的toString方法
    
  2. equals方法

    public class TestPerson{public static void main(String [] args){Person p1=new Person("王一",33,"220283...");//创建Person的对象p1;Person p2=new Person("王一",33,"220283....");//创建Person的对象p2;//调用父类Object的equals方法System.out.println(p1.equals(p2)?"是同一个人":"不是同一个人");
    }
    

对象的比较==和equals

==

  • 比较两基本类型变量的值是否相等
  • 比较两个引用类型的值即内存地址是否相等,即是否指向同一对象

equals

  • 两对象的内容是否一致

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

14.2.9 上机练习

  某汽车租赁公司出租多种车辆,车型及租金情况如下:

实现思路:

  1. 发现类

  2. 发现类的属性

  3. 发现类的方法

  4. 优化设计

  5. 编写程序入口

编写程序实现计算租赁价

MotoVehicle.java:

package com.mashibing.homework;public abstract class MotoVehicle {//定义车牌号与品牌属性private int no;private String brand;//抽象类中可以有构造方法,但是不可以进行实例化操作//为了给子类进行调用,需要写构造方法public MotoVehicle(){}public MotoVehicle(int no, String brand) {this.no = no;this.brand = brand;}public int getNo() {return no;}public void setNo(int no) {this.no = no;}public String getBrand() {return brand;}public void setBrand(String brand) {this.brand = brand;}//定义抽象方法public abstract int calcRent(int day);}

Car.java:

package com.mashibing.homework;public class Car extends MotoVehicle {private String type;//无参构造方法public Car(){}//有参构造方法public Car(String type) {type = type;}public Car(int no,String brand,String type){super(no,brand);this.type = type;}public String getType() {return type;}public void setType(String type) {this.type = type;}@Overridepublic int calcRent(int day) {//0表示别克商务。1表示宝马,2表示别克林荫大道if (type.equals("0")) {return 600 * day;} else if (type.equals("1")) {return 500 * day;} else if (type.equals("2")) {return 300 * day;} else{System.out.println("类型不匹配");return 0;}}}

Bus.java:

package com.mashibing.homework;public class Bus extends MotoVehicle{private int seatcount;//无参构造方法public Bus(){}public Bus(int seatcount) {this.seatcount = seatcount;}public Bus(int no,String brand,int seatcount){super(no,brand);this.seatcount = seatcount;}public int getSeatcount() {return seatcount;}public void setSeatcount(int seatcount) {this.seatcount = seatcount;}@Overridepublic int calcRent(int day) {if (seatcount > 16){return 1500*day;}else {return 800*day;}}
}

TestMotoVehicle.java:

package com.mashibing.homework;public class TestMotoVehicle {public static void main(String[] args) {//        MotoVehicle motoVehicle = new MotoVehicle();Car car = new Car(1,"宝马","1");System.out.println("租金是:"+car.calcRent(6));Bus bus = new Bus(2,"金龙",20);System.out.println("租金是:"+bus.calcRent(5));}
}
租金是:3000
租金是:7500

14.3 多态

  多态指的是同一个引用类型,使用不同的实例而执行不同的操作;即对于同一指令,不同对象产生不同反应。在程序中,指的是当不同对象调用同一个方法名称之后,每个对象里面具体的子类实现都是不一样的。多态性是OOP中的一个重要特性,主要是用来实现动态联编的,换句话说,就是程序的最终状态只有在执行过程中才被决定而非在编译期间就决定了。这对于大型系统来说能提高系统的灵活性和扩展性。

/*
* 多态:
*   对应同一个指令(调用同一个名称的方法),不同的对象给予不同的反应(不同的方法实现)
* 规范(多态实现的前提):
*   1.必须要有继承关系
*   2.子类方法必须重写父类方法
*   (当父类方法无法满足子类需求的时候,需要重写父类方法)
*   3.**父类引用指向子类对象**
*
* */

多态的目的:

  • 为了提高代码的扩展性和维护性
  • 方便代码逻辑的编写

案例

Pet.java:

package com.mashibing;public abstract class Pet {public abstract void feed();}

Dog.java:

package com.mashibing;public class Dog extends Pet{@Overridepublic void feed() {System.out.println("小狗在吃骨头");}
}

Cat.java:

package com.mashibing;public class Cat extends Pet{@Overridepublic void feed() {System.out.println("小猫在吃鱼");}
}

Penguin.java:

package com.mashibing;public class Penguin extends Pet{@Overridepublic void feed() {System.out.println("企鹅在吃鱼");}
}

Person.java:

package com.mashibing;public class Person {public void feed(Pet pet){pet.feed();}public static void main(String[] args) {Person person = new Person();Pet dog = new Dog();Pet cat = new Cat();Pet penguin = new Penguin();person.feed(dog);person.feed(cat);person.feed(penguin);}
}
小狗在吃骨头
小猫在吃鱼
企鹅在吃鱼

14.3.1 如何实现多态

使用多态的实现思路

  1. 编写父类

  2. 编写子类,子类重写父类方法

  3. 运行时,父类引用指向子类对象

    Pet pet = new Dog(); //自动类型转换
    

实现多态的两种形式

  • 使用父类作为方法形参实现多态
  • 使用父类作为方法返回值实现多态
package com.mashibing;/*
* 多态:
*   对应同一个指令(调用同一个名称的方法),不同的对象给予不同的反应(不同的方法实现)
* 规范(多态实现的前提):
*   1.必须要有继承关系
*   2.子类方法必须重写父类方法
*   (当父类方法无法满足子类需求的时候,需要重写父类方法)
*   3.父类引用指向子类对象
* */
public class Person {//父类作为方法形参实现多态public void feed(Pet pet){pet.feed();}//父类作为方法返回值实现多态public Pet buyPet(int type){if (type == 1){return new Dog();}else if (type == 2){return new Cat();}else{return new Penguin();}}public static void main(String[] args) {Person person = new Person();Pet dog = new Dog();Pet cat = new Cat();Pet penguin = new Penguin();person.feed(dog);person.feed(cat);person.feed(penguin);Pet pet = person.buyPet(2);//逻辑判断if (pet instanceof Dog){System.out.println("买的是一只狗");}else if (pet instanceof Cat){System.out.println("买的是一只猫");}else{System.out.println("买的是一只企鹅");}}
}

引用类型的转换

  • 引用类型的转换跟基本类型的转换类似

    • 当父类需要转成子类的时候,要进行强制转换,但是在强制转换之前一定要先判断父类引用指向子类对象到底是谁,如果无法确定,在运行过程中可能出错

      Pet pet = new Dog();
      Dog dog = (Dog)pet;
      Penguin png = (Penguin) pet;//报错,必须转换为父类指向的真实子类类型
      

      instanceof通常和强制类型转换结合使用

    • 当子类需要向父类转换的时候,直接自动转换,不需要进行任何判断

14.3.2 计算一次租赁多辆汽车的总租金

  需求说明:在前面汽车租赁系统的基础上,实现计算多种车辆总租金的功能,现在有客户租用

  • 2辆宝马
  • 1辆别克商务舱
  • 1辆金龙(34)座
  • 租5天共多少租金?

MotoVehical.java:

package com.mashibing.homework;public abstract class MotoVehicle {//定义车牌号与品牌属性private int no;private String brand;//抽象类中可以有构造方法,但是不可以进行实例化操作//为了给子类进行调用,需要写构造方法public MotoVehicle() {}public MotoVehicle(int no, String brand) {this.no = no;this.brand = brand;}public int getNo() {return no;}public void setNo(int no) {this.no = no;}public String getBrand() {return brand;}public void setBrand(String brand) {this.brand = brand;}//定义抽象方法public abstract int calcRent(int day);}

Car.java:

package com.mashibing.homework;public class Car extends MotoVehicle {private String type;//无参构造方法public Car(){}//有参构造方法public Car(String type) {type = type;}public Car(int no,String brand,String type){super(no,brand);this.type = type;}public String getType() {return type;}public void setType(String type) {this.type = type;}@Overridepublic int calcRent(int day) {//0表示别克商务。1表示宝马,2表示别克林荫大道if (type.equals("0")) {return 600 * day;} else if (type.equals("1")) {return 500 * day;} else if (type.equals("2")) {return 300 * day;} else{System.out.println("类型不匹配");return 0;}}}

Bus.java:

package com.mashibing.homework;public class Bus extends MotoVehicle{private int seatcount;//无参构造方法public Bus(){}public Bus(int seatcount) {this.seatcount = seatcount;}public Bus(int no,String brand,int seatcount){super(no,brand);this.seatcount = seatcount;}public int getSeatcount() {return seatcount;}public void setSeatcount(int seatcount) {this.seatcount = seatcount;}@Overridepublic int calcRent(int day) {if (seatcount > 16){return 1500*day;}else {return 800*day;}}
}

TestMotoVehical.java:

package com.mashibing.homework;public class TestMotoVehicle {public static void main(String[] args) {//创建车对象,放在数组中MotoVehicle[] moto = new MotoVehicle[4];moto[0] = new Car(1,"宝马","1");moto[1] = new Car(1,"宝马","1");moto[2] = new Car(1,"别克商务舱","0");moto[3] = new Bus(1,"金龙",34);//循环调用calcRent方法,计算总租金int totalMoney = 0;for (int i = 0;i < moto.length;i++){totalMoney += moto[i].calcRent(5);}System.out.println("总租金是:"+totalMoney);}
}
总租金是:15500

上机练习:购置新车

需求说明:新购置了卡车,根据吨位,租金每吨每天50,对系统进行拓展,计算汽车租赁的总租金

Track.java:

package com.mashibing.homework;public class Track extends MotoVehicle {private int weight;//无参构造方法public Track() {}//有参构造方法public Track(int weight) {this.weight = weight;}public Track(int no, String brand, int weight) {super(no, brand);this.weight = weight;}@Overridepublic int calcRent(int day) {return 50 * day * this.weight;}
}

TestMotoVehical.java:

package com.mashibing.homework;public class TestMotoVehicle {public static int calcTotal(MotoVehicle[] moto){//循环调用calcRent方法,计算总租金int totalMoney = 0;for (int i = 0;i < moto.length;i++){totalMoney += moto[i].calcRent(5);}return totalMoney;}public static void main(String[] args) {//创建车对象,放在数组中MotoVehicle[] moto = new MotoVehicle[5];moto[0] = new Car(1,"宝马","1");moto[1] = new Car(1,"宝马","1");moto[2] = new Car(1,"别克商务舱","0");moto[3] = new Bus(1,"金龙",34);moto[4] = new Track(1,"解放",50);int totalMoney = calcTotal(moto);System.out.println("总租金是:"+totalMoney);}
}
总租金是:28000

14.3.3 多态小结

类型转换

  • 向上转型——子类转换为父类,自动进行类型转换
  • 向下转型——父类转换为子类,结合instanceof运算符进行强制类型转换

实现多态的两种方式

  • 使用父类作为方法形参实现多态

  • 使用父类作为方法返回值实现多态

使用多态的好处?

  • 多态可以减少类中代码量,可以提高代码的可扩展性和可维护性

引用变量的两种类型:

  • 编译时类型(模糊一点,一般是一个父类),由声明时的类型决定。

  • 运行时类型(运行时,具体是哪个子类就是哪个子类),由实际对应的对象类型决定。

多态的存在要有3个必要条件

  • 继承
  • 方法重写
  • 父类引用指向子类对象

引用数据类型的类型转换

  • 子类转换为父类:自动转换

    • 上转型对象不能操作子类新增的成员变量和方法。
    • 上转型对象可以操作子类继承或重写的成员变量和方法
    • 如果子类重写了父类的某个方法,上转型对象调用该方法时,是调用的重写方法。
  • 父类转换为子类:强制转换

    (绝不是做手术,而是父类的真面目就是一个子类,否则会出现类型转换错误)

15.面向接口(interface)编程

接口特性

  • 接口中的所有方法都是抽象方法,不能包含方法的实现
  • 接口中的所有方法的访问修饰权限都是public abstract
  • 接口不可以被实例化
  • 接口的子类必须实现接口中的所有方法,跟抽象类有所不同,抽象类中的抽象方法必须被子类实现,抽象类中的非抽象方法是可以不被子类实现的
  • 子类可以实现多个接口
  • 接口中的变量都是静态常量,如果变量没有使用static关键字修饰,它也表示静态常量
  • 接口中的方法和常量无论是否添加public修饰,默认权限有且仅有一个,就是public

接口的使用

  1. 接口代表一种能力,接口可以定义N多个方法,子类在实现的时候,必须实现这些方法;将这些方法进行实现就意味着具备了方法的能力。面向接口编程关心实现类有何能力,而不关心实现细节。

  2. 继承:防盗门是一个门-------------------is a关系
    接口:防盗门有一个锁--------------------has a关系,接口代表一种能力
    is ahas a来判断到底是定义为继承还是定义为接口

  3. 接口是一种约定,体现在接口名称和接口注释上,有些接口只有名称,方法的实现方式要通过注释来约定。面向接口编程:程序设计时面向接口的约定而不考虑具体实现。

如何使用接口

  1. 编写接口

  2. 实现接口

  3. 使用接口

15.1 上机练习

15.1.1 使用接口实现防盗门功能

  需求说明:使用面向接口编程实现防盗门功能

  • 开门、关门
  • 上锁、开锁
  • 拍照存档

Door.java:

package com.mashibing.interfaceDemo;//定义门为抽象类并实现开门与关门功能
public abstract class Door {public abstract void openDoor();public abstract void closeDoor();}

Lock.java:

package com.mashibing.interfaceDemo;//定义锁为接口并实现开锁与关锁的功能
public interface Lock {//静态常量public static final int a = 100;public void openLock();public void closeLock();
}

DoorBell.java:

package com.mashibing.interfaceDemo;//防盗门门铃功能
public interface DoorBell {public void photo();
}

LockDoor.java:

package com.mashibing.interfaceDemo;//防盗门继承门,实现锁的接口
public class LockDoor extends Door implements Lock,DoorBell {@Overridepublic void openDoor() {System.out.println("开门");}@Overridepublic void closeDoor() {System.out.println("关门");}@Overridepublic void openLock() {System.out.println("开锁");}@Overridepublic void closeLock() {System.out.println("关锁");}@Overridepublic void photo() {System.out.println("拍照存档");}}

TestLockDoor.java:

package com.mashibing.interfaceDemo;
/*
* java中的继承关系是单继承,如果拥有多个父类的时候,可以考虑使用接口进行实现
* java中的接口具备广泛的使用
* 用法:
*   1.使用interface来修饰
*   2.接口中可以包含多个方法,且方法跟抽象类中的抽象方法一致,可以不写实现,子类在实现的时候必须实现代码逻辑
*   3.子类实现接口使用implements关键字
* 特征:
*   1.接口中的所有方法都是抽象方法,不能包含方法的实现
*   2.接口中的所有方法的访问修饰权限都是public abstract
*   3.接口不可以被实例化
*   4.接口的子类必须实现接口中的所有方法,跟抽象类有所不同,抽象类中的抽象方法必须被子类实现,抽象类中的非抽象方法是可以不被子类实现的
*   5.子类可以实现多个接口
*   6.接口中的变量都是静态常量,如果变量没有使用static关键字修饰,它也表示静态常量
*   7.接口中的方法和常量无论是否添加public修饰,默认权限有且仅有一个,就是public* */
public class TestLockDoor {public static void main(String[] args) {LockDoor lockDoor = new LockDoor();lockDoor.openDoor();lockDoor.openLock();lockDoor.closeDoor();lockDoor.closeLock();lockDoor.photo();System.out.println(LockDoor.a);}
}

运行得:

开门
开锁
关门
关锁
拍照存档
100

15.1.2 使用接口实现手机功能

需求说明

原始的手机,可以发短信,通电话。随着发展,手机增加了功能:音频、视频播放、拍照、上网

实现思路

  • 参照以下类的结构图,编写类及接口
  • 编写测试类,让普通手机播放音频、发信息和通电话,让智能手机上网、播放视频、照相、发信息和通电话

TheakePictures.java:

package com.mashibing.interfaceDemo3;//照相接口
public interface TheakePictures {public void takePictures();
}

Newwork.java:

package com.mashibing.interfaceDemo3;//连接网络接口
public interface Newwork {public void netWorkConn();
}

PlayWiring.java:

package com.mashibing.interfaceDemo3;//播放接口
public interface PlayWiring {public void play();
}

Handset.java:

package com.mashibing.interfaceDemo3;//手机抽象类,包含发短信、通电话抽象方法
public abstract class Handset {private  String brand;private  String type;public abstract void sendInfo();public abstract void call();public abstract void info();public abstract void show();public String getBrand() {return brand;}public void setBrand(String brand) {this.brand = brand;}public String getType() {return type;}public void setType(String type) {this.type = type;}
}

AptitudeHandset.java:

package com.mashibing.interfaceDemo3;//智能手机类,继承手机抽象类,并实现拍照、播放、连接网络的接口
public class AptitudeHandset extends Handset implements TheakePictures,PlayWiring,Newwork {@Overridepublic void sendInfo() {System.out.println(this.getBrand()+this.getType()+"发信息");}@Overridepublic void call() {System.out.println(this.getBrand()+this.getType()+"打电话");}@Overridepublic void info() {System.out.println(this.getBrand()+this.getType()+"收信息");}@Overridepublic void netWorkConn() {System.out.println(this.getBrand()+this.getType()+"上网");}@Overridepublic void play() {System.out.println(this.getBrand()+this.getType()+"播放视频");}@Overridepublic void takePictures() {System.out.println(this.getBrand()+this.getType()+"拍照");}@Overridepublic void show() {this.netWorkConn();this.call();this.sendInfo();this.takePictures();this.play();}
}

CommonHandset.java:

package com.mashibing.interfaceDemo3;
//普通手机类,继承手机抽象类,并实现播放接口
public class CommonHandset extends Handset implements PlayWiring{@Overridepublic void sendInfo() {System.out.println(this.getBrand()+this.getType()+"手机发信息");}@Overridepublic void call() {System.out.println(this.getBrand()+this.getType()+"手机打电话");}@Overridepublic void info() {System.out.println(this.getBrand()+this.getType()+"手机收信息");}@Overridepublic void show() {this.call();this.sendInfo();this.play();}@Overridepublic void play() {System.out.println(this.getBrand()+this.getType()+"手机播放视频");}
}

Host.java

package com.mashibing.interfaceDemo3;import java.util.Scanner;/*** 装配手机类*/
public class Host {Scanner sc=new Scanner(System.in);int brandId,typeId;//手机品牌 手机型号public Handset select(int type){Handset handset;if(type==1){//实现智能手机功能handset = new AptitudeHandset();System.out.println("1、小米 2、华为、 3、苹果");System.out.println("请选择手机品牌:");brandId=sc.nextInt();switch (brandId){case 1://设置手机品牌handset.setBrand("小米");// System.out.println(aptitudeHandset.getBrand());System.out.println("1、红米 2、小米note 3、小米8");System.out.println("请选择小米手机类型");typeId=sc.nextInt();//设置小米手机类型if(typeId==1){handset.setType("红米");}else if (typeId==2){handset.setType("小米note");}else {handset.setType("小米8");}break;case 2:handset.setBrand("华为");System.out.println("1、荣耀  2、nava  3、华为10");System.out.println("请选择华为手机类型");typeId=sc.nextInt();//设置小米手机类型if(typeId==1){handset.setType("荣耀 ");}else if (typeId==2){handset.setType("nava");}else {handset.setType("华为10");}break;default:handset.setBrand("苹果");System.out.println("1、iphone7  2、iphoneX  3、iphone9");System.out.println("请选择苹果手机类型");typeId=sc.nextInt();//设置苹果手机类型if(typeId==1){handset.setType("iphone7 ");}else if (typeId==2){handset.setType("iphoneX");}else {handset.setType("iphone9");}break;}}else{//实现普通手机功能handset=new CommonHandset();System.out.println("1、诺基亚 2、金立手机 3、三星");System.out.println("请选择普通手机品牌");brandId=sc.nextInt();switch (brandId){case 1://设置手机品牌handset.setBrand("诺基亚");System.out.println("1、210黑色直板 2、105老人备用机 3、3.1plus移动版");System.out.println("请选择诺基亚手机类型");typeId=sc.nextInt();if (typeId==1){handset.setType("210黑色直板");}else if(typeId==2){handset.setType("105老人备用机");}else {handset.setType("3.1plus移动版");}break;case 2:handset.setBrand("金立");System.out.println("1、语音王 2、A350");System.out.println("请选择金立手机类型");typeId=sc.nextInt();if(typeId==1){handset.setType("语音王");}else {handset.setType("A350");}break;default:handset.setBrand("三星");System.out.println("1、B289电信 2、E1150老人机");System.out.println("请选择三星手机类型");typeId=sc.nextInt();if(typeId==1){handset.setType("B289电信");}else {handset.setType("E1150老人机");}break;}}return  handset;}
}

Test.java

package com.mashibing.interfaceDemo3;import java.util.Scanner;/*** 测试类*/
public class Test {public static void main(String[] args) {Scanner sc=new Scanner(System.in);Host host=new Host();
//        AptitudeHandset aptitudeHandset=new AptitudeHandset();
//        CommonHandset commonHandset=new CommonHandset();Handset handset;System.out.println("1、智能手机 2、普通手机");System.out.println("请选择手机类型:");int chiooce=sc.nextInt();handset = host.select(chiooce);handset.show();}
}
1、智能手机 2、普通手机
请选择手机类型:
1
1、小米 2、华为、 3、苹果
请选择手机品牌:
2
1、荣耀  2、nava  3、华为10
请选择华为手机类型
1
华为荣耀 上网
华为荣耀 打电话
华为荣耀 发信息
华为荣耀 拍照
华为荣耀 播放视频

15.1.3 组装一台计算机

  接口是一种约定,体现在接口名称和接口注释上,有些接口只有名称;方法的实现方式要通过注释来约定。面向接口编程:程序设计时面向接口的约定而不考虑具体实现。

需求说明

  • 采用面向接口编程思想组装一台计算机

  • 计算机的主要组成部分有:CPU、硬盘、内存

实现思路

  • 定义CPU的接口CPU,返回CPU品牌和主频
  • 定义内存的接口EMS,返回容量。
  • 定义硬盘的接口HardDisk,返回容量。
  • 编写各组件厂商分别实现CPU、EMS、和HardDisk接口编写计算机类,组装计算机并显示相关信息
  • 编写测试类运行

CPU.java

package com.mashibing.interfaceDemo5;public interface CPU {//CPU品牌和主频public String getBrand();public String getHZ();
}

EMS.java:

package com.mashibing.interfaceDemo5;public interface EMS {public String getCapacity();
}

HardDisk.java:

package com.mashibing.interfaceDemo5;public interface HardDisk {public String getVolumn();
}

InterCpu.java:

package com.mashibing.interfaceDemo5;public class InterCpu implements CPU {private String brand;private String hz;public InterCpu(String brand, String hz) {this.brand = brand;this.hz = hz;}@Overridepublic String getBrand() {return this.brand;}@Overridepublic String getHZ() {return this.hz;}
}

AmdCpu.java:

package com.mashibing.interfaceDemo5;public class AmdCpu implements CPU {private String brand;private String hz;public AmdCpu(String brand, String hz) {this.brand = brand;this.hz = hz;}@Overridepublic String getBrand() {return this.brand;}@Overridepublic String getHZ() {return this.hz;}
}

SxHardDisk.java

package com.mashibing.interfaceDemo5;import com.mashibing.interfaceDemo4.Printer;public class SxHardDisk implements HardDisk {private String volumn;public SxHardDisk(String volumn) {this.volumn = volumn;}@Overridepublic String getVolumn() {return this.volumn;}
}

RAM.java:

package com.mashibing.interfaceDemo5;public class RAM implements EMS {private String capacity;public RAM(String capacity) {this.capacity  = capacity;}@Overridepublic String getCapacity() {return this.capacity;}
}

Computer.java:

package com.mashibing.interfaceDemo5;public class Computer {public void show(CPU cpu ,HardDisk hardDisk,RAM ram){System.out.println("计算机的组成如下:");System.out.println("cpu:"+cpu.getBrand()+"  ,主频是:"+cpu.getHZ());System.out.println("硬盘容量是"+hardDisk.getVolumn());System.out.println("显存大小是"+ram.getCapacity());}public static void main(String[] args) {Computer computer = new Computer();//多态InterCpu interCpu = new InterCpu("Inter", "3.8GHz");SxHardDisk sxHardDisk = new SxHardDisk("3000G");RAM ram = new RAM("4GB");computer.show(interCpu,sxHardDisk,ram);}
}

运行得:

计算机的组成如下:
cpu:Inter  ,主频是:3.8GHz
硬盘容量是3000G
显存大小是4GB

15.2 interface中的常见错误

15.3 接口总结

  1. 为什么需要接口?

    • 接口就是比“抽象类”还“抽象”的“抽象类”,可以更加规范的对子类进行约束。全面地专业地实现了:规范和具体实现的分离。
    • 接口就是规范,定义的是一组规则,体现了现实世界中“如果你是…则必须能…”的思想。
    • 接口的本质是契约,就像我们人间的法律一样。制定好后大家都遵守。
    • 项目的具体需求是多变的,我们必须以不变应万变才能从容开发,此处的“不变”就是“规范”。因此,我们开发项目往往都是面向接口编程!
  2. 接口相关规则

    • 接口中所有方法都是抽象的。

    • 即使没有显式的将接口中的成员用public表示,也是public访问类型的

    • 接口中变量默认用 public static final表示,所以接口中定义的变量就是全局静态常量。

    • 可以定义一个新接口,用extends去继承一个已有的接口

    • 可以定义一个类,用implements去实现一个接口中所有方法。

    • 可以定义一个抽象类,用implements去实现一个接口中部分方法。

  3. 如何定义接口?

    • 格式

      [访问修饰符] interface 接口名 [extends 父接口1,父接口2...]{//常量定义总是public static final//方法定义总是public abstract
      }
      
  4. 如何实现接口?

    • 子类通过implements来实现接口中的规范
    • 接口不能创建实例,但是可用于声明引用变量类型
    • 一个类实现了接口,必须实现接口中所有的方法,并且这些方法只能是public的
    • Java的类只支持单继承,接口支持多继承

注意

  • C++支持多重继承,Java支持单重继承
  • C++多重继承的危险性在于一个类可能继承了同一个方法的不同实现,会导致系统崩溃。
  • Java中,一个类只能继承一个类,但同时可以实现多个接口,既可以实现多重继承的效果和功能,也避免的多重继承的危险性。
  • 注意:extends 必须位于implements之前
  1. 接口和抽象类中的区别

    • 抽象类中的方法可以有抽象方法,也可以有普通方法;但是接口中只能包含抽象方法
    • 抽象类需要使用abstract关键字来修饰,而接口使用interface关键字修饰
    • 抽象类子类使用extends关键字来继承抽象类,使用implements来实现接口
    • 子类继承抽象类的时候必须实现所有的抽象方法,普通方法可以不重写;而接口中的所有方法必须实现
    • 抽象类中可以定义成员变量,而接口中只能定义静态常量
    • 抽象类在子类实现的时候是单继承,而接口是多继承
    • 抽象类和接口都不能实例化,但是抽象类中可以有构造方法,而接口中不能有构造方法
    • 抽象类中可以实现接口,并且不实现接口中的方法,而接口只能继承接口,不能实现接口

16. 内部类

  把一个类定义在另一个类的内部称为内部类。内部类可以轻松访问外部类的私有属性。内部类在使用时,跟之前的方法不一样,需要在内部类的前面添加外部类来进行修饰。语法:

外部类.内部类 内部类对象 = new 外部类().new 内部类();
public static void main(String [] args){Outer.Inner inner=new Outer().new Inner();//创建内部类的对象inner.print();//访问内部类的方法
}//如果主方法在外部类内部,可以省略Outer
Inner inner = out.new Inner();
  • 内部类(当做类中的一个普通成员变量,只不过此成员变量是class类型)
  • 一个java文件中可以包含多个class,但是只能有一个public class

注意事项

  • 内部类可以方便访问外部类的私有属性

  • 外部类不能直接访问内部类的成员和方法,但是如果创建了内部类的对象,此时可以在外部类中访问内部类的私有属性

  • 内部类中不能定义静态属性

  • 如果外部类和内部类具有相同的成员变量和方法,内部类默认访问自己的成员变量或方法,如果访问外部类的成员变量,需要使用this关键字外部类类名.this.属性

  • 内部类分类

    • 匿名内部类:适用只需要适用一次的类

      package com.mashibing.InnerClassDemo;/*
      *分类:
      *   匿名内部类:当定义了一个类,实现了某个接口的时候,在使用过程中只需要使用一次,没有其他用途,
      *             此时考虑到代码编写的简洁,可以考虑不创建具体的类,而采用new interface()(添加未实现的方法)就叫做匿名内部类
      * */
      public class Noname {public static void main(String[] args) {System.out.println("有一万行代码");//看起来效果像是new了一个接口,本质上是new了接口的实现类//这是省略了类名与implements关键字后的结果new Thread(new Runnable() {@Overridepublic void run() {}});System.out.println("有一万行代码");}
      }
      
    • 静态内部类:在内部类中可以定义静态内部类,使用static关键字进行修饰

      使用规则:外部类类名.内部类 内部类对象名=new 外部类类名.内部类类名();进行调用

      package com.mashibing.InnerClassDemo;/** 静态内部类:在内部类中可以定义静态内部类,使用static关键字进行修饰*           使用规则:外部类类名.内部类 内部类对象名=new 外部类类名.内部类类名();*           静态内部类可以当成一个普通的静态成员属性,通过类名.属性调用* */
      public class StaticClass {private int id;public void test(){System.out.println("test");}//静态内部类static class InnerClass {private String name;public void show() {System.out.println("show");}}public static void main(String[] args) {//创建静态内部类对象//外部类类名.内部类 内部类对象名=new 外部类类名.内部类类名();StaticClass.InnerClass innerClass = new StaticClass.InnerClass() ;}
      }
      
    • 方法内部类:将内部类定义在外部类的方法中。
      注意事项

      • 方法内部类不能在外部类的方法以外的地方使用,所以方法内部类不能使用访问控制符和static修饰符
      package com.mashibing.InnerClassDemo;/*
      * 方法内部类:将内部类定义在外部类的方法中。
      *   了解即可
      * 使用:
      *   只能在方法中创建对象,因为此class的作用域就是当前方法
      * */public class MethodInnerClass {public void show(int number){System.out.println("show");//方法内部类class InnerClass{private String name;public void test(int a){System.out.println("test");System.out.println(a);System.out.println(number);}}//需要在方法中创建方法内部类new InnerClass().test(10);}public static void main(String[] args) {MethodInnerClass methodInnerClass = new MethodInnerClass();methodInnerClass.show(1234);}
      }
      

示例

ClassDemo.java:

package com.mashibing.InnerClassDemo;public class ClassDemo {private int id;private String name;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public void show() {System.out.println("show");}class InnerClass {private int age;public void test() {System.out.println("test");//内部类可以访问外类的属性值System.out.println(id);System.out.println(name);}}
}

Test.java

package com.mashibing.InnerClassDemo;/*
* 内部类(当做类中的一个普通成员变量,只不过此成员变量是class类型):
*   一个java文件中可以包含多个class,但是只能有一个public class
*   如果一个类定义在另一个类的内部,此时可以称之为内部类
*
* 使用:
*   创建内部类的时候,跟之前的方法不一样,需要在内部类的前面添加外部类来进行修饰
*
* 特点:
*   1.内部类可以方便访问外部类的私有属性
*   2.外部类不能访问内部类的私有属性
*   3.内部类中不能定义静态属性
*
* */public class Test {public static void main(String[] args) {ClassDemo classDemo = new ClassDemo();classDemo.show();System.out.println(classDemo.getName());//使用内部类ClassDemo.InnerClass innerClass = new ClassDemo().new InnerClass();innerClass.test();}
}
show
null
test
0
null

17. 垃圾回收机制

对象空间的分配:使用new关键字创建对象即可

对象空间的释放

  • 传统的C/C++语言,需要程序员负责回收已经分配内存。

    显式回收垃圾回收的缺点:

    • 程序忘记及时回收,从而导致内存泄露,降低系统性能。
    • 程序错误回收程序核心类库的内存,导致系统崩溃。
  • Java语言不需要程序员直接控制内存回收,是由JRE在后台自动回收不再使用的内存,称为垃圾回收机制(Garbage Collection)。

    垃圾回收机制的优点:

    • 可以提高编程效率。
    • 保护程序的完整性。
    • 其开销影响性能。Java虚拟机必须跟踪程序中有用的对象,确定哪些是无用的。

垃圾回收机制的关键点

  • 垃圾回收机制只回收JVM堆内存里的对象空间。

  • 对其他物理连接,比如数据库连接、输入流输出流、Socket连接无能为力

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

  • 垃圾回收发生具有不可预知性,程序无法精确控制垃圾回收机制执行。

  • 可以将对象的引用变量设置为null,暗示垃圾回收机制可以回收该对象。

  • 程序员可以通过System.gc()或者Runtime.getRuntime().gc()来通知系统进行垃圾回收,会有一些效果,但是系统是否进行垃圾回收依然不确定。

  • 垃圾回收机制回收任何对象之前,总会先调用它的finalize方法(如果覆盖该方法,让一个新的引用变量重新引用该对象,则会重新激活对象)。

  • 永远不要主动调用某个对象的finalize方法,应该交给垃圾回收机制调用

5.Java面向对象编程相关推荐

  1. java面向对象编程知识点总结

    一:今天完成 上午详细了解了java面向对象编程的一些细节,记录如下. 1)类 是一种引用类型,包含一个签名和一个主体,主体是放在花括号里面的成员,成员包括字段和方法,还有构造方法.初始化程序和嵌套类 ...

  2. Java面向对象编程篇6——注解与反射

    Java面向对象编程篇6--注解与反射 1.注解概述 Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制 Java 语言中的类.方法.变量.参数和包等都可 ...

  3. Java面向对象编程篇5——枚举

    Java面向对象编程篇5--枚举 1.枚举的概念 在日常生活中这些事物的取值只有明确的几个固定值,此时描述这些事 物的所有值都可以一一列举出来,而这个列举出来的类型就叫做枚举类型 2.枚举的定义 使用 ...

  4. Java面向对象编程篇4——内部类

    Java面向对象编程篇4--内部类 1.内部类的概念 当一个类的定义出现在另外一个类的类体中时,那么这个类叫做内部类 (Inner),而这个内部类所在的类叫做外部类(Outer). 类中的内容:成员变 ...

  5. Java面向对象编程篇3——接口与抽象类

    Java面向对象编程篇3--接口与抽象类 1.接口(interface) 接口中可以含有变量和方法.但是要注意,接口中的变量会被隐式地指定为public static final变量(并且只能是pub ...

  6. Java面向对象编程篇2——面向对象三大特点

    Java面向对象编程篇2--面向对象三大特点 1.封装 1.1.封装的概念 通常情况下可以在测试类给成员变量赋值一些合法但不合理的数值,无 论是编译阶段还是运行阶段都不会报错或者给出提示,此时与现实生 ...

  7. Java面向对象编程篇1——类与对象

    Java面向对象编程篇1--类与对象 1.面向过程 1.1.概念 面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了 1.2.优缺点 优点:性 ...

  8. 【Java】《Java面向对象编程的三大特性》阅读笔记

    前言 偶然读到这篇文章(<Java面向对象编程的三大特性>),想来这也算论文?这种还不满网络都是?读罢觉得写得还真不错,这里以我愚见,简单点评一二,不足之处还望指教. 阅读笔记 笔记1 文 ...

  9. java面向对象编程 漫画_Java面向对象编程(一)

    由于常常将Java和C++面向对象编程的原则搞乱,所以这次把相关要点分别总结一下,本文主要总结Java面向对象编程. 面向对象编程的三大特性是:继承性(inheritance), 多态性(polymo ...

  10. Java面向对象编程入门练习:Manager类继承Employee类并实现求得员工平均业绩

    Java面向对象编程入门练习:Manager类继承Employee类并实现求得员工平均业绩 请定义一个Manager类,该类继承Employee类,并定义两个变量及一个构造方法,两个变量:depart ...

最新文章

  1. java getSource()和 getActionCommand()
  2. 一分钟明确 VS manifest 原理
  3. STM32学习之C语言知识复习
  4. 单模光纤和多模光纤的区别_一分钟了解光纤、单模光纤、多模光纤
  5. java se基础复习3
  6. 2023计算机毕业设计SSM最新选题之javaOA办公系统y7x0p
  7. maka html5,MAKA H5制作
  8. 塔夫斯大学计算机教授,塔夫茨大学工程学院虚拟教室取得成功!
  9. PTA:运算符重载(最简分数,c++)
  10. 网页崩溃原因软件测试,支招:原来这些才是APP崩溃的主要原因!资深技术大牛测试经验总结...
  11. 数据库系统期末总结(一)(往届试卷2018A卷、C卷、E卷选择题)
  12. 响应式鲜花店预订网站织梦源码
  13. YourBatman表白了,在Java 27岁生日这天
  14. 华为鸿蒙系统手表,鸿蒙2.0系统发布!年底适配最新华为旗舰,系统比安卓还要好?...
  15. VS中实时获取SVN的版本号并写入到AssemblyInfo.cs中(C#)
  16. ramdisk.img
  17. 软件设计师2010上午题基础知识(易错整理)
  18. 测试:bug的生命周期、bug的等级、如何描述一个bug
  19. eclipse护眼豆沙绿
  20. office2016增强版注册

热门文章

  1. 中国地图,世界地图js,json汉化及英文版免费下载地址
  2. lazarus生成Linux文件,Kylix的劲敌-开放源码的Lazarus[转]
  3. android lmk机制,android LMK(low memory killer) 工作机制
  4. Zynq UltraScale + RFSoC ZCU111专栏3-时钟树配置-LMK04208
  5. 开发小程序神器 wept
  6. 阿里云EMR集群搭建及使用
  7. C——char(字符串)转int
  8. 微信小程序登陆全流程及与PHP后端的交互
  9. 【大佬勿看】首次软考暂告一段落,记录一波备考经历,下次(不)再来!!(附PV操作和数据流图解析)
  10. pt100专用芯片_贴片式pt100温度传感器,生产厂家,尺寸定制,德国进口技术芯片...