第九节 三个修饰符
abstract(抽象类、抽象方法)
生活中的抽象:
搜索动物,全是动物的子类对象,却没有动物的具体对象,
不该被创建的对象:
程序是模拟现实世界,解决现实问题的,现实中存在的都是动物的子类对象,并无动物对象。所以Animal不该被独立创建成对象。
抽象类:
被abstract修饰的类,称为抽象类,抽象类意为不够完整的类,不够具体的类,抽象类对象无法独立存在,即不能new对象。
abstract class Animal{ }
抽象类的作用:
可被子类继承,为子类提供共性的属性和方法
可声明为引用,更自然的使用多态,如Animal a=new sheep(),Animal a 声明为引用了,父类引用直线指向子类对象。
经验:抽象父类,可作为子类的组成部分,依附于子类对象存在,由父类共性+子类独有,组成了完整的子类对象。
不该被实现的方法
Dog中的eat()应输出为“狗在吃骨头”Cat中的eat()应输出为“猫在吃鱼”
父类提供的方法无法满足子类不同需求,如不定义,则表示所有动物都不会吃、睡。如定义,略显多余,多数会被子类所覆盖。
方法声明必要,方法实现多余
抽象方法:
被abstract修饰的方法,称为抽象方法,只有方法声明,没有方法实现({}里的部分),意为不完整的方法,必须包含在抽象类里面。 public abstract void eat();抽象方法只能被子类重写,子类不重写,子类将是抽象类
产生继承关系之后:子类必须重写父类中所有的抽象方法,否则子类还是抽象类。
总结:
abstract修饰的类:不能new对象,但可以声明引用。Animal d=new Dog();
abstract修饰的方法:只有方法声明,没有方法实现(需包含在抽象类中)
抽象类中不一定有抽象方法,但是有抽象方法的类,一定是抽象类。
子类继承抽象类之后,必须重写父类中所有的抽象方法,否则子类还是抽象类。
static(静态的)
实例属性:
类中方法外的属性,(如:class Animal{ String breed = “dog”})这部分属性叫实例属性,实例属性是每个对象各自持有的独立的空间(多分),对象单方面修改,不会影响其他对象。
静态属性:
就是在实例属性的前面加上了static修饰,表示该属性是整个类共有的(一份),任何对象的修改,都会影响其他对象。
什么是静态:
概念:静态(static)可以修饰属性和方法。称为静态属性(类属性),静态方法(类方法)
静态成员是全类所有对象共享的成员。
在全类中只有一份,不因创建多个对象而产生多份。
访问静态成员,不必创建对象,直接通过类名点访问。
统计一个对象被创建了多少次
/*
* 多态运用在数组中,统计一个类的对象被创建了多少次
*/
package otherpractice;
public class ArrayPolymorphism{
public static void main(String[] args) {
Animal[]an=new Animal[4];
an[0]=new Dog();
an[3]=new Dog();
an[1]=new Cat();
an[2]=new Bird();
int n=0;
for(int i=0;i<an.length;i++) {
// System.out.println(an[i].eat());
an[i].eat();
if (an[i] instanceof Dog) {//统计一个类对象被创建了多少次
n++;
}
}
System.out.println(n);
}
}
class Animal{
public void eat() {
System.out.println("动物在吃");
}
}
class Dog extends Animal{
public void eat() {
System.out.println("狗在吃骨头");
}
}
class Cat extends Animal {
public void eat() {
System.out.println("猫在吃骨头");
}
}
class Bird extends Animal {
public void eat() {
System.out.println("鸟在吃骨头");
}
}
静态方法:
方法的要素:访问修饰符(public default protected private)是否是静态(static)返回值类型(void或者8中基本数据类型,或者其他自定义类)方法名(自定义,见名知意,符合标识符命名规范)方法体{ 括号里面叫方法的实现,没有括号叫方法的声明}
已知的静态方法有:Arrays.copyOf(); Arrays.sort(); Math.random(); Math.sqrt();均使用类名直接调用
静态的特点:
静态方法允许直接访问静态成员。
静态方法不能直接访问非静态成员。(刚开始学的main方法中,调用的方法全部都是由static修饰的方法,不然不能访问。)
静态方法中不允许使用this或是super关键字(静态方法是类中共有的,只有一个,this指的是当前对象,super指的是当前对象的父类对 象,直接可以通过类名点方法名来调用,不用this和super)。
静态方法可以继承,不能重写,没有多态。
动态代码块:
在实例属性之后,无参构造方法之前,用{}包起来的一部分,这个叫做动态代码块,创建对象时,触发动态代码块的执行。
执行地位:初始化属性之后,构造方法代码执行之前。
作用:可为实例属性赋值,或必要的初始行为。
运行结果:实例属性,动态代码块,构造方法。
类加载:
JVM首次使用某个类时,需通过CLASSPATH查找该类的点class文件。将点class文件中对类的描述信息加载到内存中,进行保存。
加载时机:创建对象。创建子类对象,访问静态属性,访问静态方法,主动加载:Class.forName(“全限定名”);
静态代码块:
在类中静态属性之后,静态方法之前。用static修饰的{静态代码块} 类加载时:触发静态代码块的执行(仅一次)。
执行地位:静态属性初始化之后,作用:可为静态属性赋值,或必要的初始行为。
运行结果:静态属性 静态代码块 注意:方法只有被调用才会执行。
对象的创建过程:
new之后,创建对象,触发类加载,先初始化类中静态属性,然后执行静态代码块。开始执行构造方法,执行构造方法之前,先初始化实例属性,执行动态代码块,在执行构造方法里面的代码。
带有继承关系的对象创建过程:
创建子类对象,触发类加载,先加载父类,初始化父类的静态属性,执行父类的静态代码块,接着加载子类,初始化静态属性,执行子类静态代码块,在执行自身的构造方法,构造方法里面有默认的super,开始执行父类的构造方法,开始初始化父类实例属性,执行父类动态代码块,然后执行父类构造方法,在开始初始化自身实例属性,执行自身动态代码块,然后执行自身构造方法里面的代码。
总结:
static修饰的成员为静态成员,无需创建对象,可以直接通过类名访问。
静态方法不能直接访问非静态成员
静态方法中不能用this和super
静态方法可以加继承,不能重写,没有多态
静态代码块在类加载时被执行,且只执行一次。
final(最终的,不可更改的)
final可修饰的内容
类:最终类,不可被继承,如String类,Math类,System类均为final修饰的类。
方法:最终方法,不能被重写(覆盖);
变量:所有final修饰的变量只能赋值一次,值不允许改变,成为常量(一种特殊的变量)。
final修饰的实例常量:
实例常量不在提供零值,必须手动赋予初始值。赋值时机:显式初始化;动态代码块执行时,构造方法里面。注意:如果在构造方法中为实例常赋值,必须保证所有的构造方法都能对其正确赋值。
final修饰的静态常量:
静态常量不在提供默认值,必须手动赋予初始值,赋值时机:显式初始化,静态代码块中。
final修饰的对象常量:
final修饰基本数据类型:值不可变,final修饰引用数据类型,地址不可变。
final int num=100;
num++;//final 修饰基本数据类型,值不可变
final int []arr=new int[3];
arr=new int[5];//final修饰引用数据类型,地址不可变。
final Student s = new Student();
s=new Student();
}
}
class Studnet{
String name;
}
总结:
final修饰类:此类不可被继承。
final修饰方法:此方法不能被重写(覆盖);
final修饰变量;此变量值不能改变。(无初始值、只允许赋值一次)
1.局部变量:显式初始化
2.实例常量:显式初始化、动态代码块、构造方法中
3.静态常量:显式初始化、静态代码块、
4.基本类型常量:值不可变
5.引用类型常量:地址不可变。