一、多态
1.多态介绍
多态:同类型的对象,表现出的不同形态
表现形式: 父类对象 对象名称 = 子类对象;
前提:
- 有继承/实现关系
- 有父类引用指向子类对象
- 有方法的重写
优点:使用父类型作为参数,可以接收所有子类对象,体现多态的扩展性与便利
示例:Student、Teacher继承于Person
public class Person {
private String name;
private int age;
public Person() {
}
public Person(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;
}
public void show(){
System.out.println(name + ", " + age);
}
}
public class Student extends Person {
@Override
public void show() {
System.out.println("学生的信息为:" + getName() + ", " + getAge());
}
}
public class Teacher extends Person{
@Override
public void show() {
System.out.println("老师的信息为:" + getName() + ", " + getAge());
}
}
public class Test {
public static void main(String[] args) {
Student s = new Student();
s.setName("张三");
s.setAge(23);
Teacher t = new Teacher();
t.setName("阿玮");
t.setAge(30);
register(s);
register(t);
}
public static void register(Person p){
p.show();
}
}

2.多态调用成员的特点
变量调用:编译看左边,运行也看左边
方法调用:编译看左边,运行看右边
public class Test {
public static void main(String[] args) {
Animal a = new Dog();
//调用成员变量:编译看左边,运行也看左边
//编译看左边:Javac编译代码的时候,会看左边的父类中有没有这个变量,如果有,编译成功,否则编译失败
//运行也看左边:Java运行代码的时候,实际获取的就是左边父类中成员变量的值
System.out.println(a.name);//动物
//调用成员方法:编译看左边,运行看右边
//编译看左边Javac编译代码的时候,会看左边的父类中有没有这个方法,如果有,编译成功,否则编译失败
//运行看右边:Java运行代码的时候,实际上运行的是子类的方法
a.show();//Dog --- show方法
}
}
class Animal{
String name = "动物";
public void show(){
System.out.println("Animal --- show方法");
}
}
class Dog extends Animal{
String name = "狗";
@Override
public void show() {
System.out.println("Dog --- show方法");
}
}
3.多态的劣势
不能使用子类的特有功能
解决方法:使用强制类型转换
Person p = new Student();
Student s = (Student)p;
强制类型转换:
- 可以转换成真正的子类类型,从而调用子类独有的功能
- 转换类型与真是对象类型不一致会报错
- 转换的时候用instanceof关键字进行判断
public class Test {
public static void main(String[] args) {
Animal a = new Dog();
//编译看左边,运行看右边
a.eat();
//多态的弊端
//不能调用子类的特有功能
//报错的原因?
//当调用成员方法的时候,编译看左边,运行看右边
//那么在编译的时候会先检查左边的父类中有没有这个方法,如果没有直接报错。
//a.lookHome();
//解决方案:
//变回子类类型就可以了
// Dog d = (Dog) a;
//
// d.lookHome();
//新特性
//先判断a是否为Dog类型,如果是,则强转为Dog类型,转换之后变量名为d
//如果不是,则不强转,结果直接是false
if (a instanceof Dog d){
d.lookHome();
}
}
}
class Animal{
public void eat(){
System.out.println("动物在吃东西");
}
}
class Dog extends Animal{
@Override
public void eat() {
System.out.println("够吃骨头");
}
public void lookHome(){
System.out.println("狗看家");
}
}
二、包
包的作用:包就是文件夹,用来管理各种不同功能的Java类
书写规则:公司域名反写+包的作用,需要全部英文小写,见名知意
包名+类名 = 全类名
导包场景:
- 使用同一个包中的类时,不需要导包
- 使用java.lang包中的类时,不需要导包
- 其他情况都需要导包
- 如果同时使用两个包中的同名类,需要用全类名
// 1. 使用java.lang包中的类,无需导入
public class ImportExample {
public static void main(String[] args) {
// String和System都属于java.lang包,不需要导入
String message = "Hello, World!";
System.out.println(message);
// 2. 使用同一个包中的类,无需导入
SamePackageClass samePackageObj = new SamePackageClass();
samePackageObj.doSomething();
// 3. 使用其他包中的类,需要导入
importExample.util.UtilityClass util = new importExample.util.UtilityClass();
util.help();
// 4. 当使用两个包中的同名类时,需要使用全类名
importExample.data.User user1 = new importExample.data.User();
importExample.model.User user2 = new importExample.model.User();
user1.setName("Data User");
user2.setName("Model User");
System.out.println(user1.getName());
System.out.println(user2.getName());
}
}
// 同一个包中的类,无需导入即可使用
class SamePackageClass {
public void doSomething() {
System.out.println("Doing something in same package class");
}
}
三、final
final修饰方法:
表明该方法是最终方法,不能被重写

final修饰类:
表明该类是最终类,不能被继承

final修饰变量:
叫做常量,只能被赋值一次

四、权限修饰符
作用范围
| 修饰符 | 同一个类中 | 同一个包中其他类 | 不同包下的子类 | 不同包下的无关类 |
|---|---|---|---|---|
| private | √ | |||
| 默认空 | √ | √ | ||
| protected | √ | √ | √ | |
| public | √ | √ | √ | √ |
使用规则:
实际开发中,一般只用priva和public
- 成员变量私有
- 方法公开
- 特例:如果方法中的代码是抽取其他方法中共性代码,这个方法一般也私有
五、代码块
分类:局部代码块、构造代码块、静态代码块
局部代码块的作用:
提前结束变量的生命周期(已淘汰)

构造代码块的作用:
抽取构造方法中的重复代码,每次创建对象时,在构造方法执行之前运行。
private String name;
// 构造代码块
{
System.out.println("执行构造代码块:初始化公共逻辑");
}
// 构造方法1
public Person() {
System.out.println("执行无参构造方法");
}
// 构造方法2
public Person(String name) {
this.name = name;
System.out.println("执行有参构造方法,name=" + name);
}
public static void main(String[] args) {
new Person(); // 先执行构造代码块,再执行无参构造
new Person("Alice"); // 先执行构造代码块,再执行有参构造
}

静态代码块的作用:
数据的初始化,类加载时(仅执行一次),优先于构造代码块和构造方法。
public class Person {
// 静态代码块
static {
System.out.println("执行静态代码块:加载配置");
}
// 构造代码块
{
System.out.println("执行构造代码块");
}
public Person() {
System.out.println("执行构造方法");
}
public static void main(String[] args) {
System.out.println("main方法开始");
new Person(); // 触发对象创建
new Person(); // 静态代码块不会再执行
}
}

923

被折叠的 条评论
为什么被折叠?



