1.什么是多态
同一种事物表现出来的多种形态
2.多态的前提
- 必须有继承关系或者实现接口关系
- 必须有方法重写
- 必须有父类引用指向子类对象
3.多态的格式
- 父类类名 对象名 =new 子类类名();
4.多态的注意事项:
- 多态下子类和父类出现同名的成员变量时,访问父类的成员变量();
- 多态下子类和父类出现同名的成员变量时,访问父类的成员变量();
5.绑定
- 成员变量的静态绑定:在编译期就确定变量是访问父类的还是子类的
- 成员方法的动态绑定:在编译期还不确定调用父类的还是子类的方法,是在程序运行过程确定
- 注意:编译看左边,运行看右边
- 成员变量编译看左边,运行也看左边(看父类有没有这个方法,没有的话向下转型)
- 成员方法编译看左边,运行看右边
- 注意:编译看左边,运行看右边
6.多态的优点
- 提高代码的复用性
- 提供代码的维护性
7.多态的缺点
父类引用不能调用子类特有的成员方法
8.多态用于形参或者返回值
1. 多态用于形式参数的好处:可以接受各种子类类型的对象
2. 多态用于方法返回值的好处:可以返回各种子类类型的对象
-
代码
-
package com.itheima._04多态优缺点; /** 目标:理解多态的优点与缺点 讲解: 1. 多态的优点 提高代码的复用性 提高代码的维护性 2. 多态的缺点:父类引用不能调用子类特有的成员方法 小结: 多态的优点:提高代码的复用性和维护性 思考:多态后如何调用子类特有的功能? */ public class Demo042 { public static void main(String[] args) { // 买1只?:创建Dog对象 Dog d1 = new Dog(); // 让狗吃骨头 /* d1.eat(); // 让狗睡觉 d1.sleep();*/ feedAnimal(d1); // 又买一只 Dog d2 = new Dog(); // 让狗吃骨头 /*d2.eat(); // 让狗睡觉 d2.sleep();*/ feedAnimal(d2); System.out.println("----------------"); // 买一只猫 Cat c1 = new Cat(); /*c1.eat(); c1.sleep();*/ feedAnimal(c1); // 买一只猫 Cat c2 = new Cat(); /*c2.eat(); c2.sleep();*/ feedAnimal(c2); Animal d3 = createAnimal(1); Animal c3 = createAnimal(2); } /** * 负责创建动物对象 * type = 1 狗 * type = 2 猫 * @return */ //返回值 public static Animal createAnimal(int type){ if (type == 1){ return new Dog(); } else if (type == 2) { return new Cat(); } return new Tiger(); } // 喂养动物 // Animal a = new Dog(); // Animal a = new Cat(); //形参 public static void feedAnimal(Animal a){ // 让狗睡觉 a.sleep(); // 让狗吃骨头 a.eat(); } }
9.基本数据类型的转换格式
-
小==》大 double a=100;
-
大==》小 double b=122.5; int c=(int)b
-
多态转型的分类:
- 向上转型:父类引用指向子类对象的过程是向上转型的结果
- 格式:父类类名 变量名=new 子类类名();
- 向下转型:父类引用转换为子类引用的过程
- 格式:子类类名 变量名=(子类类名)父类的引用;
10.instanceof关键字的使用
-
判断父类引用指向哪个子类类型 常用多态之后判断父类引用指向哪个子类类型的对象
-
格式:boolean b= 父类引用 instanceof 子类类名;
===============================
11.内部类的概述
在一个类中有定义了一个类,在A类定义了B类,A类称为外部类,B类则称为内部类。
12.内部类的分类
- 静态内部类:定义在外部类的成员位置(有static修饰)
- 使用格式:class Outer{static class InnerP{} }
- 实例内部类:定义在外部类的成员位置(没有static修饰)
- 局部内部类:定义在外部类的成员方法中
- 匿名内部类:没有名字的类,常用作为方法参数!
13.静态内部
package com.itheima._08静态内部类_了解;
/**
Tip:静态内部类与外部类的⽤法完全一样。只是访问的时候需要加上外部类.内部类。
目标:了解静态内部类定义和使用
讲解:
1. 静态内部类的使用格式
class Outer {
static class Inner{
}
}
2. 静态内部类对象创建格式
外部类名.内部类名 变量名 = new 外部类名.内部类名(参数);
3. 静态内部类只能访问外部类的static修饰的成员?这句话对吗?
正确
小结:
1. 静态内部类对象创建格式:
外部类名.内部类名 变量名 = new 外部类名.内部类名(参数);
*/
class Outer {
private String name;
// 静态内部类
static class Inner{
// 定义成员变量
private int age;
// 定义构造方法
public Inner(int age) {
this.age = age;
}
public Inner() {
}
// 定义成员方法
public void show(){
System.out.println("年龄:" + age + ", 姓名:");
}
}
// 外部类方法:创建内部对象
public void showInfo(){
Inner inner = new Inner();
inner.show();
}
}
public class Demo081 {
public static void main(String[] args) {
// 创建静态内部类对象
/*Outer.Inner i = new Outer.Inner(20);
// 调用对象调用方法
i.show();*/
// 创建外部类对象
Outer outer = new Outer();
outer.showInfo();
}
}
14.实例内部
package com.itheima._09实例内部类_了解;
/**
实例内部类又称为成员内部类
目标:了解实例内部类的使用
讲解:
1. 实例内部类的定义格式
class Outer {
class Inner{
}
}
2. 实例内部类创建对象格式
外部类名.内部类名 变量名 = new 外部类名().new 内部类名();
3. 实例内部类的好处
可以访问外部类的任意成员。
小结:
1. 实例内部类创建对象格式:
外部类.内部类 变量名= new 外部类名(参数).new 内部类名(参数);
2. 实例内部类的好处
可以访问外部类所有成员
*/
class Outer {
// 成员变量
private static String name;
public Outer() {
}
public Outer(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// 实例内部类
class Inner{
private int age;
public Inner() {
}
public Inner(int age) {
this.age = age;
}
public void show(){
System.out.println("年龄:" + age+",外部类name:" + name);
}
}
}
public class Demo091 {
public static void main(String[] args) {
// 外部类名.内部类名 变量名 = new 外部类名().new 内部类名();
Outer.Inner i = new Outer("jack").new Inner(30);
// 调用方法
i.show();
}
}
package com.itheima._09实例内部类_了解;
/*
面试题:请在?地⽅写上相应代码,以达到输出的效果
目标:了解实例内部类如何访问外部类同名的成员变量
讲解:
小结:
如何访问外部类的成员变量:外部类名.this.成员变量名;
*/
public class Demo092 {
public static void main(String[] args) {
Body.Heart heart = new Body().new Heart();
heart.jump();
}
}
class Body { // 身体
private int weight = 30;
// 在成员位置定义一个类
class Heart {
private int weight = 20;
public void jump() {
int weight = 10;
System.out.println("心脏在跳动 " + weight); // 10
System.out.println("心脏在跳动 " + this.weight);// 20
System.out.println("心脏在跳动 " + Body.this.weight); // 30
Body.this.jump();
}
}
public void jump() {
System.out.println("外部类jump方法...");
}
}
15.局部内部类
package com.itheima._10局部内部类_了解;
/**
目标:了解局部内部类的创建和使用
讲解:
1. 什么是局部内部类:
定义在外部类的方法中
2. 局部内部类的使用:
只能在方法内部使用
3. 局部内部类注意事项:
* 静态方法中的内部类只能访问外部类的静态成员。
* 非静态方法中的内部类可以访问外部类静态成员和非静态成员。
小结:
1. 什么是局部内部类: 定义方法中类
2. 局部内部类的使用: 只能在定义的方法中使用
*/
class Outer{
private static String name;
public static void test(){
// 定义局部内部类
class Inner{
// 定义成员变量
private int age;
public Inner(int age) {
this.age = age;
}
public Inner() {
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void show(){
System.out.println("年龄:" + age + ",姓名:" + name);
}
}
// 创建局部类对象
Inner inner = new Inner(40);
inner.show();
}
}
public class Demo101 {
public static void main(String[] args) {
// 创建外部类对象
Outer outer = new Outer();
outer.test();
}
}
16.11@匿名内部类
package com.itheima._11匿名内部类_重要;
/**
目标:掌握匿名内部类的语法
讲解:
1. 匿名内部类概述
没有名字的类
2. 使用匿名内部类的前提条件
必须有一个已知类或已知接口
直接创建已知类的子类对象
直接创建已知接口的实现类对象
3. 匿名内部类的格式
new 类名或接口名(){ }
小结:
1. 匿名内部类的语法:
new 类名或接口名(){
重写方法
}
*/
public class Demo111 {
public static void main(String[] args) {
// 使用匿名内部类:直接创建Animal类的子类对象
/**
下面代码等价这两行:
1. class Xxx extends Animal{
@Override
public void eat() {
System.out.println("吃饭....");
}
}
2. Animal a = new Xxx();
3. a.eat();
*/
Animal a = new Animal(){
@Override
public void eat() {
System.out.println("吃饭....");
}
};
a.eat();
// 直接创建已经接口的实现类对象
/**
下面代码等价两行
1. class Yyy implements Smoking{
@Override
public void smoke() {
System.out.println("抽烟...");
}
}
2. Smoking s = new Yyy();
3. s.smoke();
*/
Smoking s = new Smoking(){
@Override
public void smoke() {
System.out.println("抽烟...");
}
};
s.smoke();
}
}
=回顾=
17.代码块
-
静态代码块 :类中方法外 static{}
- 特点:类加载的时候会自动执行 只会执行一次
- 作用:常用执行一次的
-
实例代码块:每次创建对象都会自动执行一次 {}
package com.itheima._12代码块概述;
/**
目标:学习静态代码块和构造代码块
讲解:
1. 代码块分类
静态代码块
构造代码块
2. 静态代码块概述
特点:在类加载的时候会自动执行,只会执行1次
语法:static { }
作用:常用执行一次性初始化操作
3. 实例代码块概述
特点:每次创建对象都会自动执行一次
语法:{ }
4. 代码块的定义位置
类中方法外
小结
1. 静态代码块格式: static {}
2. 实例代码块格式: { }
*/
public class Demo121 {
public static void main(String[] args) {
// 创建学生对象
Student stu01 = new Student();
Student stu02232323 = new Student();
/* System.out.println(stu01.getAge());*/
System.out.println(stu01.getName());
}
}
18.包
- 包的概念:包在文件系统中就是文件夹
- 包的作用:用来解释类命名冲突的问题 将功能相似或相同的类放在一起便于管理
- 包的定义格式和命名规范:package 包名
- 包名一般是小写字母 公司域名倒着写 com.itheima
18.导包
- 导包方式使用 :
- import 包名.包名—类名;一个类
- import 包名.包名.*; 通配符 导入其他包的所有类
2.类全名字符串:当类名一样的时候
- 包名.包名…类名
19.访问权限
- private:只能在本类中使用
- 默认(null)权限:可以在本包下的类访问
- protected:可以在本包下的类以及其他包有关联的子类访问
- public:可以在任意包下的任意类访问
20.Object类
-
特点:最大 所以类的父亲
- 类object是类层次结构的跟类
- 每个类都使用object作为超类父类基类
- 所有类都是直接或者间接继承object类
-
Oject类常用方法
默认返回格式:类全名字符串@对象在内存中的地址值
调用时机:
自动调用:当打印输出对象时系统内部会自动调用
手动调用:通过对象调用
用来比较两个对象是否相同,是则返回true 否则false
默认是通过比较两个对象的地址值判断是否相同 除非重写才是比较内容
==比较运算符
基本数据类型:比较两个变量值是否相同
引用数据类型:比较两个对象的地址值
@equals方法的作用:
比较两个对象是否相同 默认是通过地址值比较
重写equals方法的目的:
不希望比较地址判断,而是希望比较对象内容判断是否相同
!!!判断是不是同一个类
if (obj == null || !(obj instanceof Student)) return false;
等价于
@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); }
总结:
package com.itheima._16toString方法;
import java.util.Objects;
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
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 void showInfo(){
System.out.println("name = " + name + ", age = " + age);
}
/*@Override
public String toString() {
return "name = " + this.name + ", age = " + this.age;
}*/
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
// 重写equals方法:要比较两个对象的内容判断是否相同
// Object obj = new Student("小泽", 20);
/* @Override
public boolean equals(Object obj) {
// this ==> s1
// obj ==> s2
// 判断obj是否是this
if (this == obj) return true;
// 判断obj是否为null
// 判断obj是否是Student对象
if (obj == null || !(obj instanceof Student)) return false;
// 向下转型:将obj转换Student
Student s2 = (Student)obj;
// 判断姓名是否相同
if (!this.name.equals(s2.name)) return false;
// 判断年龄是否相同
if (this.age != s2.age) return false;
// 来到这里说明姓名和年龄都相同
return true;
}
*/
@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);
}
}
-
21.工具类
-
Objects 类概述:是一个工具类 类中的所有方法都是静态方法
-
常用的工具类 Arrays Objects Collection Math System
-
static boolean isNull(Object obj)判断对象obj是否为null 是返回true
-
static boolean equals(Object a,Object b)比较对象a和对象b是否相同 相同为true
-
Object.equals(x,y) Object.isNull(x)
- 对于比较优先使用 Object.equals(x,y)
- s1=null; if(s1!=null){sout(s1.equals(s2))}; 要先判断是否为空
- sout( Object.equals(s1,s2) ); 推荐使用 因为已经判断了是否为空
22.总结
- 能够说出使用多态的前提条件
必须是子父类关系或类实现接口关系
必须有方法重写
必须是父类引用指向子类对象
- 理解多态的向上转型
父类类型 变量名 = new 子类类型();
接口类型 变量名 = new 实现类类型();
- 理解多态的向下转型
父类引用转换为子类引用的过程
子类类型 变量名 = (子类类型)父类引用;
- 能够写出静态代码块的格式
static {
}
- 能够说出权限修饰符作用范围
private:只能在本类使用
默认:本包下的类
protected:本包下的类或子类
public:任何包下任意类
- 说出内部类的概念
在A类中定义了B类,B类就是内部类,A类称为外部类
- 能够说出Object类的特点:所有类的父类
- 能够重写Object类的toString方法:
通过IDEA快速生成即可
重写目的:在打印对象时希望输出对象的成员变量值
- 能够重写Object类的equals方法:
通过IDEA快速生成即可
重写目的:希望比较内容判断两个对象是否相同。
1. 多态(重点)
概念:同一种事物表现出来的多种形态
前提:
* 有子父类关系或类实现接口关系
* 要有方法重写
* 父类引用指向子类对象
格式:父类引用指向子类对象:
父类类型 变量名 = new 子类类型();
接口类型 变量名 = new 实现类类型();
好处:提供代码复用性和维护性
缺点:不能访问子类特有的功能
应用场景:
作为方法形式参数:可以接收各种子类类型的数据
作为方法返回值:可以返回各种子类类型的数据
转型:
向上转型:父类引用指向子类对象
向下转型:将父类引用强制转换为子类引用
instanceof关键字:
判断父类引用指向的子类类型
父类引用 instanceof 子类类型
Smoking s = new Student();
boolean b = s instanceof Student
2. 内部类(匿名内部类重点)
匿名内部类语法:
new 类名或接口名(){ }
直接创建已知类的子类对象或已知接口的实现类对象
3. 代码块
4. 包
5. 权限修饰符
6. Object特点和常用方法(重点)
7. Objects工具类