思维导图
一、abstract
1.1 抽象类
举例
package com.robot.month1.week2.day20200728;
/**
* 动物抽象类。
*
* @author 张宝旭
*/
public abstract class Animal {
private String name;
private int age;
public Animal() {
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 吃
*/
public abstract void eat();
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;
}
}
特点
- 抽象类不能被实例化
- 抽象类中可以包含抽象方法,也可包含方法体
- 包含抽象方法的类,一定是抽象类
- 子类必须实现抽象类中的所有抽象方法,除非子类也是抽象类
1.2 抽象方法
特点
- 没有方法体
- 包含抽象方法的类,一定是抽象类
- 抽象方法必须被子类重写,除非子类也是抽象类
1.3 小练习
有一个交通工具类TracficTool,属性: brand, 方法: run()
有三个子类Bicycle、 Car、SubWay
主人类:属性:name,方法:goHome(交通工具)
使用抽象类抽象方法优化
/**
* 交通工具抽象类。
*
* @author 张宝旭
*/
public abstract class TracficTool {
private String brand;
public TracficTool() {
}
public TracficTool(String brand) {
this.brand = brand;
}
public abstract void run();
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
}
/**
* 自行车。
*
* @author 张宝旭
*/
public class Bicycle extends TracficTool{
public Bicycle() {
}
public Bicycle(String brand) {
super(brand);
}
@Override
public void run() {
System.out.println(super.getBrand() + " run");
}
}
/**
* 小汽车。
*
* @author 张宝旭
*/
public class Car extends TracficTool{
public Car() {
}
public Car(String brand) {
super(brand);
}
@Override
public void run() {
System.out.println(super.getBrand() + " run");
}
}
/**
* 地铁。
*
* @author 张宝旭
*/
public class SubWay extends TracficTool{
public SubWay() {
}
public SubWay(String brand) {
super(brand);
}
@Override
public void run() {
System.out.println(super.getBrand() + " run");
}
}
/**
* 主人。
*
* @author 张宝旭
*/
public class Master {
private String name;
public Master() {
}
public Master(String name) {
this.name = name;
}
public void goHome(TracficTool tracficTool) {
System.out.println(this.name + " 坐着 " + tracficTool.getBrand() + " 回家了");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
/**
* 测试。
*
* @author 张宝旭
*/
public class Test {
public static void main(String[] args) {
Master master = new Master("小张");
TracficTool bicycle = new Bicycle("自行车");
TracficTool car = new Car("小汽车");
TracficTool subway = new SubWay("地铁");
master.goHome(car);
}
}
// 结果示例
小张 坐着 小汽车 回家了
二、static
static用法
- 静态属性
- 静态方法
- 静态代码块
- 静态内部类
- 静态导入
2.1 实例属性
每个对象各自持有的独立空间,不影响
Student s1 = new Student();
s1.count;
Student s2 = new Student();
s2.count;
2.2 静态属性
整个类共同持有的共享空间
static int count;
静态属性应该使用 类名.属性
来访问
Student.count;
静态成员存在方法区中
JDK7之前在永久代
JDK8之后在元空间
2.3 静态方法
特点
- 静态方法中可以访问静态方法或静态属性
public static void countStudents() {
Student.count = 125;
}
- 静态方法中不可以访问非静态方法或非静态属性
public static void run() {
name = "zbx"; // 错误,不可以方法静态属性
}
- 非静态方法可以访问静态方法或静态属性
public void sort() {
Student.count = 125;
}
- 静态方法中不允许使用this或super关键字
- 静态方法可以继承,不能重写、没有多态。
- 静态成员可以直接通过类名访问
- 在类加载时执行,只执行一次
测试
/**
* 学生类。
* 测试static
*
* @author 张宝旭
*/
public class Student {
static int studentCount;
String name;
public static void count() {
System.out.println("Student " + Student.studentCount);
}
public void run() {
System.out.println(this.name + " run");
}
}
/**
* 测试学生类。
*
* @author 张宝旭
*/
public class StudentTest {
public static void main(String[] args) {
Student student = new Student();
student.name = "小张"; // 调用非静态属性
student.run(); // 调用非静态方法
Student.studentCount += 125; // 调用静态属性
Student.count(); // 调用静态方法
}
}
2.4 代码块
2.4.1 局部代码块
放在局部代码块中的内容,可以缩小使用范围,提前释放内存空间
public static void main(String[] args) {
int num = 12;
{
int age = 25;
}
}
测试
不使用局部代码块
public class Temp {
public static void main(String[] args) {
int num1 = 12;
int num2 = 25;
int num3 = 99;
}
}
使用javap -v Temp 查看
使用局部代码块
/**
* @author 张宝旭
*/
public class Temp {
public static void main(String[] args) {
int num1 = 12;
{
int num2 = 25;
System.out.println(num2);
}
int num3 = 99;
}
}
使用javap -v Temp 查看
可以看到,num2和num3使用的是同一个内存空间
因为num2在局部代码块中,使用完之后就会提前释放空间,所以为sum3分配空间的时候又分配了同样的内存空间
2.4.2 动态代码块
创建对象时执行,静态属性初始化之后执行
作用:可以为静态属性赋值,初始化作用
/**
* @author 张宝旭
*/
public class DyTest {
static int count;
{
count = 125;
}
public static void main(String[] args) {
}
}
反编译查看代码
public class DyTest
{
static int count;
public DyTest()
{
count = 125;
}
public static void main(String args1[])
{
}
}
可以看到并没有动态代码块,而是将动态代码块中的内容放到了构造方法中(先执行动态代码块,后执行构造方法)
2.4.3 静态代码块
/**
* @author 张宝旭
*/
public class StaticTest {
static int count;
// 静态代码块在类加载时只执行一次
static {
count = 125;
}
public static void main(String[] args) {
System.out.println(StaticTest.count);
}
}
面试题
- 先在内存中初始化开辟空间,demo=null count1=0 count2=0
- 然后执行
private static Demo demo = new Demo();
创建对象的过程中调用了构造方法,所以count1=1,count2=1- 然后执行
public static int count1;
没有赋值,所以count1还是1- 然后执行
public static int count2=0;
赋值为0,所以count2变为0- 最后执行
Demo.show();
方法打印出结果,执行结果为count1:1 count2:0
2.5 对象创建过程
父类静态属性
父类静态代码块
子类静态属性
子类静态代码块
父类实例属性
父类动态代码块
父类构造方法
子类实例属性
子类动态代码块
子类构造方法
三、final
概念:最终的,不可更改的
final可修饰的内容:类、方法、变量
final修饰的类,不能被继承
final修饰的方法,不能被覆盖(但是可以被继承)
final修饰的变量,不能被更改(常量)
- 实例常量
final String name;
:显示初始化,可在动态代码块、构造方法中赋值 - 静态常量
static final String name;
:显示初始化,可在静态代码块中赋值
static final int sum;
static {
sum = 12;
}
- 对象常量
final int[] array = new int[12];
:引用类型, 地址不可变
abstract 不能和 final 同时使用:因为 abstract 必须重写,而 final 不能重写
abstract 不能和 static 同时使用:因为 static 修饰的是静态方法,可以直接被类调用,而 abstract 修饰的是抽象方法,没有方法体