一、多态【重点】【掌握】
1.1 概述
-
生活中的多态
- 事物在人脑中的主观印象
- 狗--》动物
-
程序中的多态
- 声明的变量类型是父类类型
- 创建的对象类型是子类类型
- 父类变量存储的是子类对象的地址
- 父类引用指向子类对象
1.2 多态的特点
-
多态方式创建对象只能使用声明的类型中的属性和方法
- 方法存在重写
- 属性不存在覆盖【访问的属性依旧是父类中的内容】
-
如果方法被子类重写,执行的是重写之后的方法
1.3 动态使用--父类声明为方法形参【重点】【掌握】
- 能接收父类和子类类型的对象
Human
package com.shine.polymorphic01;
public class Human {
public void dance() {
System.out.println("人跳舞是为了祭天酬神");
}
}
Man
package com.shine.polymorphic01;
public class Man extends Human {
@Override
public void dance() {
System.out.println("男人喜欢tiao迪斯科");
}
}
Woman
package com.shine.polymorphic01;
public class Woman extends Human {
@Override
public void dance() {
System.out.println("女人喜欢跳广场舞");
}
}
Demo01
package com.shine.polymorphic01;
public class Demo01 {
public static void main(String[] args) {
/**
* 展示人跳舞的信息
*/
// 正常创建对象
Human human = new Human();
dance(human);
Man man = new Man();
dance(man);
Woman woman = new Woman();
dance(woman);
}
/**
* 展示跳舞的方法
* @param human
*/
public static void dance(Human human) {
human.dance();
}
}
1.4 多态使用-声明为方法返回值类型【重点】【掌握】
- 能返回父类和子类类型的对象
Auto
package com.shine.polymorphic02;
/**
* 所有车子的父类
*/
public class Auto {
public void run() {
System.out.println("车子能行驶");
}
}
Bus
package com.shine.polymorphic02;
public class Bus extends Auto {
@Override
public void run() {
System.out.println("公交车载人");
}
}
Car
package com.shine.polymorphic02;
public class Car extends Auto {
}
Demo01
package com.shine.polymorphic02;
import java.util.Scanner;
public class Demo01 {
public static void main(String[] args) {
/**
* 编写方法买车,输出车子的编号,返回对应类型的车
*/
System.out.println("欢迎来到红浪漫汽车店,请选择您需要的车子【1==小轿车,2==公交车,3==拖拉机,4==摩托车】:");
// 提示输入并获取车子型号
Scanner sc = new Scanner(System.in);
int autoNo = sc.nextInt();
// 调用方法获取对象
Auto auto = buyAuto(autoNo);
System.out.println(auto.getClass());
}
/**
* 买车的方法
* @param autoNo 车子的编号
* @return 车子对象
*/
public static Auto buyAuto(int autoNo) {
Auto auto = null;
switch (autoNo) {
case 1:
auto = new Car();
break;
case 2:
auto = new Bus();
break;
case 3:
auto = new Tractor();
break;
case 4:
auto = new MotoBike();
break;
default:
auto = new Auto();
break;
}
return auto;
}
}
1.5 类型转换
向上转型
- 声明的类型是父类,实际引用指向【保存对象的地址】的对象是子类
- 天生安全,多态的核心使用方式
向下转型
- 声明的类型是子类,引用执行父类
- 有风险,可能造成类型转换异常
Animal
package com.shine.polymorphic03;
public class Animal {
public void eat() {
System.out.println("动物需要进食...");
}
}
Cat
package com.shine.polymorphic03;
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫咪喜欢吃鱼");
}
}
Dog
package com.shine.polymorphic03;
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗子喜欢吃肉");
}
}
Demo01
package com.shine.polymorphic03;
public class Demo01 {
public static void main(String[] args) {
/**
* 父类
* Animal
* 子类
* Dog
* Cat
*/
// 正常创建对象:声明的类型和实际创建的类型是相同的
Animal a = new Animal();
// 动态方式创建对象:声明的类型是父类,实际创建对象是子类类型
// 向上转型
Animal aa = new Dog();
// 向下转型
Dog dog = (Dog) aa;
System.out.println(dog.getClass());
// 向下转型,声明类型和对象类型不匹配,报错:java.lang.ClassCastException
//Cat cat = (Cat) aa;
//System.out.println(cat.getClass());
// 判定对象是否属于指定类型
System.out.println(aa instanceof Animal);
System.out.println(aa instanceof Dog);
System.out.println(aa instanceof Cat);
}
}
1.6 练习题
父类声明为方法形参
-
Worker父类
- Cook
- Driver
- Programmer
-
编写方法,展示这个工人工作的方式
父类声明为方法返回值类型
-
编写方法点餐,返回下面类型的对象之一
-
Food父类
- 东坡肉
- 西湖醋鱼
- 扬州炒饭
- 鸭血粉丝汤
-
展示食物的信息
二、抽象
2.1 概述
-
使用abstract修饰的内容成为抽象
- 抽象类
- 抽象方法
2.2 抽象类
* 在Java中有些累不适合直接创建对象
* 创建的对象不能准确表示现实中的任何对象
* 应该限制其创建对象
* 使用abstract修饰类,这样的类成为抽象类,不能直接创建对象
抽象类Human
package com.shine.abstract01;
/**
* 抽象类Human
* 创建的对象不够具体,限制创建对象
*/
public abstract class Human {
String name;
int age;
String gender;
public void eat() {}
public void sleep() {}
}
抽象类的作用
-
当前其他类的父类
- 提供多个子类中共有的属性和方法
-
在创建对象时候声明为父类类型
- 更自然的使用多态
package com.shine.abstract01;
public class Woman extends Human {
}
package com.shine.abstract01;
public class Demo01 {
public static void main(String[] args) {
/**
* 在Java中有些累不适合直接创建对象
* 创建的对象不能准确表示现实中的任何对象
* 应该限制其创建对象
* 使用abstract修饰类,这样的类成为抽象类,不能直接创建对象
*/
// 声明的类型父类,创建的对象类型是子类
Human h01 = new Man();
Human h02 = new Woman();
}
}
2.3 抽象方法
-
有些方法在父类中定义,方法的实现部分多余
- 动物类类中吃饭的方法:动物都会吃饭,吃饭的方式多数不同,子类一般需要重写这些方法
- 可以把方法的声明部分保留,实现部分删除,定义成为抽象方法
-
如果父类中存在抽象方法
- 子类重写所有抽象方法
- 或者子类也是抽象类
Auto抽象类
package com.shine.abstract02;
public abstract class Auto {
public abstract void start();
public void stop() {
System.out.println("车子需要能停止");
}
}
Car
package com.shine.abstract02;
public class Car extends Auto {
@Override
public void start() {
System.out.println("小轿车使用电启动");
}
}
Tractor
package com.shine.abstract02;
public class Tractor extends Auto {
@Override
public void start() {
System.out.println("拖拉机使用摇把启动");
}
}
Demo01
package com.shine.abstract02;
public class Demo01 {
public static void main(String[] args) {
Auto auto01 = new Car();
auto01.start();
auto01.stop();
}
}
三、static
3.1 概述
-
被static修饰的内容成为静态的内容
- static修饰的变量成为静态属性,也称为类属性
- static修饰的方法成为静态方法,也称为类方法
- 静态的数据随着类的加载而加载,无需等待对象创建即可使用【使用类名直接调用】
3.2 静态变量【掌握】
- 使用static修饰的变量成为静态变量
- 此类创建的所有对象共用一个静态变量
- 如果在任何位置修改了静态变量,其他所有对象都会收到影响
Korean
package com.shine.static01;
public class Korean {
String name;
int age;
// 类变量
static String capital = "汉城";
public void show() {
System.out.println("Korean [name=" + name + ", age=" + age + ", capital=" + capital + "]");
}
}
Demo01
package com.shine.static01;
public class Demo01 {
public static void main(String[] args) {
// 静态属性 == 类属性,跟随类一起加载进入内存,无序创建对象即可使用
System.out.println(Korean.capital);
// 创建对象
Korean k01 = new Korean();
k01.name = "李二顺";
k01.age = 18;
k01.show();
Korean k02 = new Korean();
k02.name = "金三顺";
k02.age = 23;
k02.show();
k01.age = 19;
k01.show();
k02.show();
System.out.println("--------------------------");
// k02.capital = "首尔";
// 静态的数据存储在方法区,和类对象放在一起,是类变量,推荐使用类名直接调用
Korean.capital = "首尔";
k01.show();
k02.show();
}
}
3.3 课堂案例
- 统计一个类在运行期间创建了多少对象
package com.shine.static01;
public class User {
String name;
// 静态的属性,用来记录创建对象的次数
private static int count = 0;
public User() {
count++;
}
public User(String name) {
this.name = name;
count++;
}
public static int getCount() {
return count;
}
}
package com.shine.static01;
public class Demo02 {
public static void main(String[] args) {
/**
* User
* 统计一个类在运行期间创建了多少对象
*/
for (int i = 0; i < 150; i++) {
new User();
}
System.out.println(User.getCount());
}
}
3.4 静态方法【掌握】
- 使用static修饰的方法成为静态方法【类方法】
- 可以使用类名直接调用【不用创建对象即可调用】
- 静态方法中只能访问静态数据,不能访问非静态数据、不能访问this、super
package com.shine.static01;
public class User {
String name = "张三";
// 静态的属性,用来记录创建对象的次数
private static int count = 0;
public User() {
count++;
}
public User(String name) {
this.name = name;
count++;
}
public static int getCount() {
return count;
}
// 实例方法
public void show() {
// 实例方法访问实例属性和静态属性
System.out.println(name);
System.out.println(count);
// 实例方法调用实例方法和静态方法
showStatic();
System.out.println(this);
}
// 静态方法
public static void showStatic() {
// 实例属性需要先创建对象才能使用,静态方法中不能访问实例遍历【静态早于实例】
// System.out.println(name);
System.out.println(count);
// 静态的方法不能调用非静态的方法
// show();
// System.out.println(this);
// System.out.println(super);
}
}
四、代码块
4.1 概述
-
代码块就是使用{}包裹的一块代码
-
没有名字,自动执行
-
根据位置和修饰符可以分为:
- 局部代码块
- 动态代码块【构造代码块、成员代码块】
- 静态代码块
- 同步代码块【多线程部分讲解】
4.2 局部代码块
- 定义在方法中的代码块称为局部代码块
- 自动执行,无需【无法】手动调用
package com.shine.block;
public class Demo01 {
public static void main(String[] args) {
// 局部变量
int num = 100;
System.out.println("Hello001");
System.out.println("Hello002");
{
System.out.println("我是局部代码块");
System.out.println(num);
int ii = 200;
System.out.println(ii);
}
System.out.println("Hello003");
System.out.println("Hello004");
// System.out.println(ii);
}
}
4.3 动态代码块
- 动态代码块也称为构造代码块
- 位置和构造器同一级:类中方法外
- 构造代码块每一次创建对象都自动执行一次,执行时间早于构造器
- 可以把构造方法中共同的内容抽取出来放在构造代码块中执行
4.4 静态代码块【掌握】
- 使用static修饰的代码块成为静态代码块
- 位置和构造器同一级:类中方法外
- 静态代码块在程序运行过程中最多执行一次
- 适用于类的初始化,一般加载驱动使用
package com.shine.block;
public class User {
String name;
static int count = 0;
static {
System.out.println("静态代码块");
}
{
System.out.println("构造代码块");
count++;
}
public User() {
System.out.println("无参数构造器");
}
public User(String name) {
this.name = name;
System.out.println("有参数构造器");
}
public static int getCount() {
return count;
}
}
4.5 同步代码块
- 多线程线程安全问题时候讲解