目录
一、面向对象三大特征之三:多态
1.多态的概述、多态的形式
什么是多态:同类型的对象,执行同一个行为,会表现出不同的行为特征
多态的常见形式:父类类型 对象名称 = new 子类构造器; 接口 对象名称 = new 实现类构造器
多态中成员的访问特点:1.方法调用:编译看左边,运行看右边;2.变量调用:编译看左边,运行也看左边(多态侧重行为多态)
多态的使用前提:有继承/实现关系;有父类引用指向子类对象;有方法重写
package com.pikaqiu.d1_polymorphic;
public abstract class Animal {
public String name = "父类动物";
public abstract void run();
}
package com.pikaqiu.d1_polymorphic;
public class Dog extends Animal{
public String name = "狗动物" ;
@Override
public void run() {
System.out.println("🐕跑的贼快");
}
}
package com.pikaqiu.d1_polymorphic;
public class Tortoise extends Animal{
public String name = "乌龟动物" ;
@Override
public void run() {
System.out.println("🐢根本跑不起来");
}
}
package com.pikaqiu.d1_polymorphic;
public class Test {
public static void main(String[] args) {
//多态形式:父类类型 对象名称 = new 子类构造器
Animal a = new Dog();
a.run(); //编译看左边,运行看右边
System.out.println(a.name); //编译看左边,运行还是看左边
Animal a1 = new Tortoise();
a1.run();
System.out.println(a1.name);
}
}
2.多态的优势
多态的优势:1.在多态的形式下,右边对象可以实现解耦合,便于扩展和维护;2.定义方法的时候,使用父类型作为参数,该方法就可以接收这个父类的一切子类对象,体现出多态的扩展性与便利
多态下会产生的问题:多态下不能使用子类独有的功能
3.多态下引用数据类型的类型转换
自动类型转换(从子到父):子类对象赋值给父亲类型的变量指向
强制类型转换(从父到子):此时必须进行强制类型转换---子类 对象 = (子类)父亲类型的变量
作用:可以解决多态下的劣势,可以实现调用子类独有的功能
注意:如果转换后的类型和对象真实类型不是同一种类型,那么转换时,编译不会出错,但是运行会出现ClassCastException问题
Java建议强制转换前使用instanceof判断当前对象的真实类型,再进行强制转换
package com.pikaqiu.d2_polymorphic_convert;
public class Animal {
public void run(){
System.out.println("动物可以跑");
}
}
package com.pikaqiu.d2_polymorphic_convert;
public class Dog extends Animal{
@Override
public void run(){
System.out.println("🐕跑的很快");
}
public void lookDoor(){
System.out.println("🐕在看🚪");
}
}
package com.pikaqiu.d2_polymorphic_convert;
public class Tortoise extends Animal{
@Override
public void run(){
System.out.println("🐢跑的很慢");
}
public void layEggs(){
System.out.println("🐢在下蛋");
}
}
package com.pikaqiu.d2_polymorphic_convert;
public class Test {
public static void main(String[] args) {
//自动类型转换
Animal a = new Dog();
a.run();
//强制类型转换
Animal a1 = new Tortoise();
a1.run();
//a1.layEggs();
//Dog d = (Dog) a1; //强制类型转换,编译阶段不报错(有继承或者实现关系,编译阶段可以强制转换),运行时可能出错
if(a1 instanceof Tortoise){
Tortoise t = (Tortoise) a1;
t.layEggs();
}else if(a1 instanceof Dog){
Dog d = (Dog) a1;
d.lookDoor();
}
}
}
4.多态的案例
需求:使用面向对象编程模拟:设计一个电脑对象,可以安装2个USB设备;鼠标:被安装时可以完成插入、调用点击功能、拔出功能;键盘:被安装时可以完成插入、调用打字功能、拔出功能;
package com.pikaqiu.d3_polymorphic_test;
public interface USB {
void insert();
void pullOut();
}
package com.pikaqiu.d3_polymorphic_test;
public class Mouse implements USB{
@Override
public void insert() {
System.out.println("鼠标完成接入");
}
@Override
public void pullOut() {
System.out.println("鼠标已经拔出");
}
public void click(){
System.out.println("开始点击");
}
}
package com.pikaqiu.d3_polymorphic_test;
public class KeyBoard implements USB{
@Override
public void insert() {
System.out.println("键盘完成接入");
}
@Override
public void pullOut() {
System.out.println("键盘已经拔出");
}
public void type(){
System.out.println("开始打字");
}
}
package com.pikaqiu.d3_polymorphic_test;
public class Computer {
public void installUSB(USB usb){
//接入
usb.insert();
//独有功能
if(usb instanceof KeyBoard){
KeyBoard k = (KeyBoard) usb;
k.type();
}else if(usb instanceof Mouse){
Mouse m = (Mouse) usb;
m.click();
}
//拔出
usb.pullOut();
}
}
package com.pikaqiu.d3_polymorphic_test;
public class Test {
public static void main(String[] args) {
Computer c = new Computer();
USB u = new KeyBoard();
c.installUSB(u);
USB u1 = new Mouse();
c.installUSB(u1);
}
}
二、内部类
1.内部类的概述
内部类就是定义在一个类里面的类,里面的类可以理解成(寄生),外部类可以理解成(宿主)
内部类的使用场景,作用:1.当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部的事物提供服务,那么整个内部的完整结构可以选择使用内部类设计;2.内部类通常可以方便访问外部类的成员,包括私有成员;3.内部类提供了更好的封装性,内部类本身就可以用private、protected等修饰,封装性可以做更多的控制
内部类的分类:1.静态内部类(了解);2.成员内部类(非静态内部类)(了解);3.局部内部类(了解);4.匿名内部类(重点)
2.内部类之一:静态内部类(了解)
什么是静态内部类:1.有static修饰;2.它的特点和使用与普通类是完全一样的,类有的成分它都有,只是位置在别人里面而已
静态内部类创建对象的格式:外部类名.内部类名 对象名 = new 外部类名.内部构造器;
使用场景:一个类中包含了一个完整的成分,如汽车类中的发动机类
静态内部类中是否可以直接访问外部类的静态成员?可以,外部类的静态成员只有一份可以被共享访问
静态内部类中是否可以直接访问外部类的实例成员?不可以,外部类的实例成员必须使用外部类对象访问
3.内部类之二:成员内部类(了解)
什么是成员内部类:1.无static修饰,属于外部类的对象;2.JDK16之前,成员内部类中不能定义静态成员,JDK16开始也可以定义静态成员了
成员内部类创建对象的格式: 外部类名.内部类名 对象名 = new 外部类构造器.new 内部类构造器();
成员内部类中是否可以直接访问外部类的静态成员?可以,外部类的静态成员只有一份可以被共享访问
成员内部类中是否可以直接访问外部类的实例成员?可以,因为必须先有外部类对象,才能有成员内部类对象,所以可以直接访问外部类对象的实例成员
案例:
package com.pikaqiu.d5_innerclass;
public class Test2 {
public static void main(String[] args) {
People.Heart heart = new People().new Heart();
heart.show();
}
}
class People{
private int heartbeat = 150;
public class Heart{
private int heartbeat = 110;
public void show(){
int heartbeat = 78;
System.out.println(heartbeat); //78
System.out.println(this.heartbeat); //110
System.out.println(People.this.heartbeat); //150
}
}
}
4.局部内部类(鸡肋语法,了解即可)
1.局部内部类放在方法、代码块、构造器等执行体中;
2.局部内部类的类文件名为:外部类$N内部类.class
5.匿名内部类(重点)
什么是匿名内部类:本质上是一个没有名字的局部内部类,定义在方法中、代码块中、等
作用:方便创建子类对象,最终目的为了简化代码编写
new 类 || 抽象类名 || 接口名(){重写方法};
特点:1.匿名内部类是一个没有名字的内部类;2.匿名内部类写出来就会产生一个匿名内部类的对象;3.匿名内部类的对象类型相当于是当前new的那个类型的子类类型
package com.pikaqiu.d6_innerclass_anonymous;
import static sun.misc.PostVMInitHook.run;
public class Test {
public static void main(String[] args) {
Animal a = new Animal() {
@Override
public void run() {
System.out.println("老虎跑得快~~~");
}
};
a.run();
}
}
//class Tiger extends Animal{
//
// @Override
// public void run() {
// System.out.println("老虎跑的快~~~");
// }
//}
abstract class Animal{
public abstract void run();
}
6.匿名内部类常见使用形式
使用总结:匿名内部类可以作为方法的实际参数进行传递
package com.pikaqiu.d6_innerclass_anonymous;
public class Test2 {
public static void main(String[] args) {
// Swimming s = new Swimming() {
// @Override
// public void swim() {
// System.out.println("学生快乐的自由泳");
// }
// };
go(new Swimming() {
@Override
public void swim() {
System.out.println("学生快乐的自由泳");
}
});
}
public static void go(Swimming s){
System.out.println("开始");
s.swim();
System.out.println("结束");
}
}
class Student implements Swimming{
@Override
public void swim() {
System.out.println("学生快乐的自由泳");
}
}
interface Swimming{
void swim();
}
7.匿名内部类真实使用场景演示
package com.pikaqiu.d6_innerclass_anonymous;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Test3 {
public static void main(String[] args) {
//1.创建窗口
JFrame win = new JFrame("登录界面");
JPanel panel = new JPanel();
win.add(panel);
//2.创建一个按钮对象
JButton btn = new JButton("登录");
// //注意:匿名内部类的使用
// btn.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
// JOptionPane.showMessageDialog(win,"你是傻子");
// }
// });
btn.addActionListener(e -> JOptionPane.showMessageDialog(win,"说爱我"));
//3.把按钮对象添加到桌布展示
panel.add(btn);
//4.展示窗口
win.setSize(400,300);
win.setLocationRelativeTo(null);
win.setVisible(true);
}
}
三、常用API
1.Object
Object类的作用:1.一个类要么默认继承了Object类,要么间接继承了Object类,Object类是Java中的祖宗类;2.Object类的方法是一切子类可以直接使用的
toString存在的意义:父类toString()方法存在的意义就是为了被子类重写,以便返回对象的内容信息,而不是地址信息
equals存在的意义:父类equals方法存在的意义就是为了被子类重写,以便子类自己来定制比较规则
package com.pikaqiu.d7_api_object;
import java.util.Objects;
public class Student { //extends Object
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
package com.pikaqiu.d7_api_object;
public class Test {
public static void main(String[] args) {
Student s = new Student("皮卡丘",18);
//System.out.println(s.toString());
//直接输出对象变量,默认可以省略toString调用
System.out.println(s);
}
}
package com.pikaqiu.d7_api_object;
public class Test2 {
public static void main(String[] args) {
Student s1 = new Student("皮卡丘",18);
Student s2 = new Student("皮卡丘",18);
System.out.println(s1.equals(s2));
System.out.println(s1 == s2);
}
}
2.Objects
Objects类是Object的子类,Objects类是从JDK 1.7开始之后才有的
Objects的equals方法与Object里的equals方法比较的结果是一样的,但是更安全
package com.pikaqiu.d8_api_objects;
import java.util.Objects;
public class Test {
public static void main(String[] args) {
String s1 = null;
String s2 = new String("pikaqiu");
//System.out.println(s1.equals(s2)); //错误,会出现空指针异常
/**
* public static boolean equals(Object a, Object b) {
* return (a == b) || (a != null && a.equals(b));
* }
*/
System.out.println(Objects.equals(s1, s2)); //更安全,结果更准确
System.out.println(Objects.isNull(s1)); //true
System.out.println(s1 == null);
}
}
3.StringBuilder
StringBuilder是一个可变的字符串类,我们可以把它看成是一个对象容器
作用:提高字符串的操作效率,如拼接、修改等
package com.pikaqiu.d9_api_stringbulider;
public class StringBuilderDemo1 {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
sb.append("a");
System.out.println(sb); //a
StringBuilder sb1 = new StringBuilder();
sb1.append("a").append("b").append("c").append("就这");
System.out.println(sb1); //abc就这
//反转
sb1.reverse();
System.out.println(sb1); //这就cba
//求长度
System.out.println(sb1.length());
//注意:StringBuilder只是拼接字符串的手段,效率好
//最终结果还是要恢复成String类型
StringBuilder sb2 = new StringBuilder();
sb2.append("123").append("456");
//恢复成String
String rs = sb2.toString();
check(rs);
}
public static void check(String data){
System.out.println(data);
}
}
案例:
package com.pikaqiu.d9_api_stringbulider;
public class StringBuilderTest2 {
public static void main(String[] args) {
int[] arr1 = null;
System.out.println(toString(arr1));
int[] arr2 = {11,22,33,44};
System.out.println(toString(arr2));
int[] arr3 = {};
System.out.println(toString(arr3));
}
public static String toString(int[] arr){
if(arr != null){
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < arr.length; i++) {
sb.append(arr[i]).append(i == arr.length - 1 ? "" : ",");
}
sb.append("]");
return sb.toString();
}else {
return null;
}
}
}
4.Math
Math类包含执行基本数字运算的方法,Math类没有提供公开的构造器
package com.pikaqiu.d10_math;
public class MathDemo {
public static void main(String[] args) {
//取绝对值,返回正数
System.out.println(Math.abs(-10.5)); //10.5
//向上取整
System.out.println(Math.ceil(4.3)); //5.0
//向下取整
System.out.println(Math.floor(3.2)); //3.0
//求指数次方
System.out.println(Math.pow(3,2)); //3^2=9
//四舍五入
System.out.println(Math.round(4.52)); //5
System.out.println(Math.random()); //0.0-1.0中的随机一个数(包前不包后)
//拓展:3-9直接的随机整数
//[0-6] + 3
int data = (int)(Math.random() * 7) + 3;
System.out.println(data);
}
}
5.System
System的功能是通用的,都是直接用类名调用即可,所以System不能被实例化
package com.pikaqiu.d11_system;
import java.util.Arrays;
public class SystemDemo {
public static void main(String[] args) {
System.out.println("程序开始~~~");
//System.exit(0); //JVM终止
//计算机认为时间起源:返回1970-1-1 00:00:00 走到此刻的总的毫秒值(时间毫秒值)
long time = System.currentTimeMillis();
System.out.println(time);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
System.out.println(i);
}
long endTime = System.currentTimeMillis();
System.out.println((endTime - startTime) / 1000.0 + "s");
//数组拷
/**
* arraycopy(Object src, int srcPos,Object dest, int destPos,int length);
* 参数一:被拷贝的数组
* 参数二:从哪个索引位置开始拷贝
* 参数三:复制的目标数组
* 参数四:粘贴位置
* 参数五:拷贝元素的个数
*/
int[] arr1 = {10,20,30,40,50,60};
int[] arr2 = new int[5]; //[0,0,40,50,60]
System.arraycopy(arr1,3,arr2,2,3);
System.out.println(Arrays.toString(arr2));
System.out.println("程序结束~~~");
}
}
6.BigDecimal
用于解决浮点型运算失真的问题