一、多态【重点】【掌握】
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 同步代码块
-
多线程线程安全问题时候讲解