三个修饰符
abstract:(自然、强制实现多态)为了更自然的使用多态。抽象方法只声明不实现。不能创建对象new anmial,父类唯独不能独立使用构造方法创造对象。一般用于抽象类作为父类,子类将抽象方法覆盖。
static:(类)静态方法可以被继承,不能被覆盖,不能多态。不必创建对象,可直接通过类名访问,本类直接方法名,其他类通过类名.调用。
final:(最终)方法不能被继承,不能被覆盖,变量不能被修改,初始化需要赋值。
一、abstract
//更像是为多态的使用制定的一种规范。
//抽象类,更自然的使用多态。//强制使用Animal a = new Dog();
//抽象方法,只声明,不实现。
//抽象类中不一定有抽象方法,但有抽象方法的类一定是抽象类。
1.1 必要性:
现实中存在的都是"动物"具体的子类对象,并不存在"动物"对象,像Animal不应该被独立创建成对象。
不该被实现的方法:
方法声明必要,方法实现多余。
1.2 抽象类:
概念和应用:
Animal是抽象的,无法实例化。
被abstract修饰的类,称为抽象类。
抽象类意为不够完整的类、不够具体的类,抽象类对象无法独立存在,即不能new对象。
抽象类的作用:
1.可被子类继承,提供共性属性和方法。
2.可声明为引用,更自然的使用多态。//强制使用Animal a = new Dog();
语法:
abstract class Animal {
}
1.3 抽象方法:
被abstract修改的方法,称为抽象方法,
只有方法声明,没有方法实现({}的部分)。
意为不完整的方法,必须包含在抽象类中。
产生继承关系后,子类必须重写父类中所有的抽象方法,否则子类还是抽象类。
语法:
public abstract void eat();//抽象方法,只有声明,没有实现,不够完整。
1.4 经验:
抽象父类,可作为子类的组成部分,依附于子类对象存在,由父类共性+子类独有组成完整的子类对象。
抽象方法:(abstract只有方法的声明,实现多余,因为它只是用来提供有这个方法)
被abstract修改的方法,称为抽象方法,只有方法声明,没有方法实现({}的部分)。意为不完整的方法,必须包含在抽象类中。
1.5 总结:
- abstract修饰类:不能new对象,但可以声明引用。
- abstract修饰方法:只有方法声明,没有方法实现。(需包含在抽象类中)
- 抽象类中不一定有抽象方法,但有抽象方法的类一定是抽象类。
- 子类继承抽象类后,必须重写父类中所有的抽象方法,否则子类还是抽象类
1.6 代码实现:
//父类
abstract class Animal {//逻辑:不够完整、不够具体
String breed;
int age;
String sex;
public Animal(){
System.out.println("父类唯独不能独立使用构造方法创造对象");
}
// public void eat(){
// System.out.println("动物在吃。。");
// }
public abstract void eat();//抽象方法:只有声明,没有实现(不够完整)
public void sleep(){}
}
//子类
public class Dog extends Animal {
String furColor;
public Dog(){
super();
System.out.println("从子类调");
}
public void eat(){
System.out.println("狗吃");
}
public void run(){
}
}
//测试
public class TestAbstract {
public static void main(String[] args){
//错误 new Animal();//Error 不能独立存在
//正确 new Dog();//Correct
Animal a = new Dog();
System.out.println(a.breed);
a.eat();
}
}
二、static(类属性、方法)
//无需创建对象,通过类名访问。
//静态方法访问静态成员,不能访问非静态成员。
//可以继承,不能覆盖,没有多态。
2.1 实例属性:
实例属性是每个对象各种持有的独立空间(多份),对象单方面修改,不会影响其他对象。
//每个栈中的地址对应一个堆中的地址。
public class TestStaticField{
public static void main(String[] args){
MyClass mc1 = new MyClass();
mc1.a = 100;
MyClass mc2 = new MyClass();
mc2.a = 200;
System.out.println(mc1.b+"\t"+mc2.b);
}
}
class MyClass{
int a;
}
输出结果:
100 200
2.2 静态属性(类属性):
静态属性是整个类共同持有的共享空间(一份),任何对象修改,都会影响其他对象。
public class TestStaticField{
public static void main(String[] args){
MyClass mc1 = new MyClass();
mc1.b = 100;
MyClass mc2 = new MyClass();
mc2.b = 200;
System.out.println(mc1.b+"\t"+mc2.b);
System.out.println(Myclass.b);//可以通过类名直接访问。
}
}
class MyClass{
static int b;//静态属性
}
输出结果:
200 200
200
2.3 什么是静态:(一般全类计数用的变量,只有一份。)
-
静态(static)可以修饰属性和方法。
-
称为静态属性(类属性)、静态方法(类方法)。
-
静态成员是全类所有对象共享的成员。
-
在全类中只有一份,不因创建多个对象而产生多份。
-
不必创建对象,可直接通过类名访问。
2.4 静态方法:
public class TestStaticMethod{
public static void main(String[] args){
MyClass.method1();//可在其他类中,通过“类名.静态方法名”访问。
}
class MyClass{
public static void method1(){
System.out.println("MyClass static method1()");
method2();//可在本类中,通过“静态方法名”访问。
}
public static void method2(){//由static修饰的静态方法。
System.out.println("MyClass static method2()");
}
}
}
//静态方法可在其他类中通过“类名.静态方法名”访问。不用new。
//实例方法则是伴随的对象的产生才能调用。
已知静态方法:
Arrays.copyOf();
Arrays.sort();
Math.random();
Math.sqrt();
均使用类名直接调用
2.5 静态的特点:
- 静态方法允许直接访问静态成员。
- 静态方法不能直接访问非静态成员。
- 静态方法中不允许使用this或是super关键字。
- 静态方法可以继承,不能覆盖,没有多态。
public class A {
static int field;
public static void staticMethod(){//静态方法只能调用静态属性,不能调用非静态方法
System.out.println(field);
}
}
public class TestAccessNotStatic {
public static void main(String[] args){
A.staticMethod();//通过类名直接调用。
//静态方法是可以通过类名调用的(在调用该方法时,可能从未创建过对象)
}
}
//可以使用继承,无需创建对象,直接通过类名调用,无需创建对象。
//子类
public class B extends A{
}
//测试类:
public class TestAccessNotStatic {
public static void main(String[] args){
A.staticMethod();//通过类名直接调用。
//静态方法是可以通过类名调用的(在调用该方法时,可能从未创建过对象)
B.staticMethod();//继承通过类名直接调用,无需创建对象。
}
}
2.6 局部代码块:
局部代码块,会缩小变量的使 用范围,提前释放局部变量, 节省内存。
public class TestLocalBlock{
public static void main(){
int num=100;
{
int age = 20;
System.out.println(age);
System.out.println(num);
}
int num2 = 500;
System.out.println(num);
System.out.println(num2);
}
}
运行结果:
20
100
100
500
2.7 动态代码块:
//没太大用,构造方法可以替代。
//写在类下面的代码块是动态代码块。执行对象便执行动态代码块。先执行动态代码块再执行构造方法。
创建对象时,触发动态代码块的执行。
执行地位:初始化属性之后、构造方法代码之前。
作用:可为实例属性赋值,或必要的初始行为
public class TestDynamicBlock{
public static void main(String[] args){
new MyClass();
}
}
class MyClass{
String field = "实例属性";
public MyClass(){
System.out.println("构造方法");
}
{
System.out.println(field);
System.out.println("动态代码块");
}
}
结果:
实例属性
动态代码块
构造方法
2.8 类加载:
1.JVM首次使用某个类时,需通过CLASSPATH查找该类的.class文件。
2.将.class文件中对类的描述信息加载到内存中,进行保存。
javap命令
java -verbose:class xxx//观察加载的类
javap -verbose xxx > xxx.bytecode//反编译文件
如:包名、类名、父类、属性、方法、构造方法…
加载时机:
- 创建对象。
- 创建子类对象。
- 访问静态属性。
- 调用静态方法。
- 主动加载:Class.forName(“全限定名”);//主动加载一个类
2.9 静态代码块:
//静态代码块是由类加载触发的。类加载便执行静态代码块,静态属性初始化之后,只会执行一次。
类加载时,触发静态代码块的执行(仅一次)。
执行地位:静态属性初始化之后。
作用:可为静态属性赋值,或必要的初始行为。
public class TestStaticBlock{
public static void main(String[] args){
MyClass.method();
}
}
class MyClass{
static String sField = "静态属性";
static{
System.out.println(sField);
System.out.println("静态代码块");
}
public static void method(){
/*无代码
*只为触发静态属性的初始化
*和静态代码块的执行
*/
}
}
运行结果:
静态属性
静态代码块
执行顺序总结:
public class Super {
static String staticField = "父类静态属性";
static {
System.out.println(staticField);
System.out.println("父类静态代码块");
}
String instanceField = "父类实例属性";
{
System.out.println(instanceField);
System.out.println("父类实例代码块");
}
public Super(){
System.out.println("父类构造方法");
}
}
public class TestLoadSort {
public static void main(String[] args){
new Super();
}
}
执行结果:
父类静态属性
父类静态代码块
父类实例属性
父类实例代码块
父类构造方法
//父类
public class Super {
static String staticField = "父类静态属性";
static {
System.out.println(staticField);
System.out.println("父类静态代码块");
}
String instanceField = "父类实例属性";
{
System.out.println(instanceField);
System.out.println("父类实例代码块");
}
public Super(){
System.out.println("父类构造方法");
}
}
//子类
public class Sub extends Super {
static String staticField1 = "子类静态属性";
static {
System.out.println(staticField1);
System.out.println("子类静态代码块");
}
String instanceField1 = "子类实例属性";
{
System.out.println(instanceField1);
System.out.println("子类实例代码块");
}
public Sub(){
System.out.println("子类构造方法");
}
}
//测试类
public class TestLoadSort {
public static void main(String[] args){
new Sub();
}
}
执行结果:
父类静态属性
父类静态代码块
子类静态属性
子类静态代码块
父类实例属性
父类实例代码块
父类构造方法
子类实例属性
子类实例代码块
子类构造方法
//只修改测试类
public class TestLoadSort {
public static void main(String[] args){
new Sub();
new Sub();
}
}
执行结果:
父类静态属性
父类静态代码块
子类静态属性
子类静态代码块
父类实例属性
父类实例代码块
父类构造方法
子类实例属性
子类实例代码块
子类构造方法
父类实例属性
父类实例代码块
父类构造方法
子类实例属性
子类实例代码块
子类构造方法
总结:
• static修饰的成员为静态成员,无需创建对象,可直接通过类名访问。
• 静态方法不能直接访问非静态成员。
• 静态方法中不能使用this或super。
• 静态方法可以继承、不能重写、没有多态。
• 静态代码块在类加载时被执行,且只执行一次
三、final(最终类、属性、方法)
3.1 final可修饰的内容:
类(最终类)
方法(最终方法)
变量(最终变量)
3.2 final类:
1.final修饰类:此类不能被继承。
String、Math、System均为final修饰的类,不能被继承。
2.final修饰类:此方法不能被覆盖。
意为最终方法,不支持子类以覆盖的形式修改。
3.3 final变量
变量:字面常量、符号常量
final修饰变量:此变量值不能被改变(常量)
所有的final修饰的变量只能赋值一次,值不允许改变。
//错误案例
public class TestFinal{
public static void main(String[] args){
final int num = 10;
//num = 20;//错误用法,无法为最终变量num分配值
}
}
3.3.1 实例变量:
实例常量不再提供默认值,必须手动赋予初始值。//其值不能改变
赋值时机:显示初始化、动态代码块、构造方法。
注意:如果在构造方法中为实例常量赋值,必须保证所有的构造方法都能对其正常赋值。
//错误案例
public class TestFinal{
public static void main(String[] args){
new Student();
}
}
class Student{
//final String name;// = "Tom"//错误:可能尚未初始化变量name
{
//正确
//方法块外final String name;
name = "tom";
//或者
final String name = "tom";
}
public Student(){
//正确
final String name = "tom";
}
}
3.3.2 静态常量:
静态常量不再提供默认值,必须手动赋予初始值。
赋值时机:显示初始化、静态代码块。
public class TestFinal{
public static void main(String[] args){
System.out.println(Student.SCHOOL_NAME);
}
}
class Student{
//static final String SCHOOL_NAME;//="xx小学"//错误:可能尚未初始化变量SCHOOL_NAME
static{
//正确
//SCHOOL_NAME = "北京市第一中学";
//静态常量不再提供默认值,必须手动赋予初始值。
//赋值时机显示初始化、静态代码块。
}
}
3.3.3 对象常量:
public class TestFinal{
public static void main(String[] args){
final int num = 100;
//错误
//num += 20;//final修饰基本类型:值不可变
final int[] nums = new int[]{11,22,33};
//正确
//nums[0] = 88;
//错误
//nums = new int[5];//final修饰引用类型:地址不可变
final Student s = new Student();
//错误
//s = new Student();//
}
}
class Student{
String name;
}
3.4 总结:
• final修饰类:此类不能被继承。 (最终类)
• final修饰方法:此方法不能被覆盖。 (最终方法)
• final修饰变量:此变量值不能被改变。(最终变量)(无初始值、只允许赋值一次)
- 局部常量:显示初始化。
- 实例常量:显示初始化、动态代码块、构造方法。
- 静态常量:显示初始化、静态代码块。
- 基本类型常量:值不可变。
• 引用类型常量:地址不可变。
• abstract不能和final同时使用。
• abstract不能和static同时使用
2.final类不能被子类重写,但是可以被子类继承。
final变量:
常量:字面常量、符号常量//fianl修饰局部变量变成常量。
final修饰变量:此变量值不能被更改。
//final修饰实例变量(常量),赋值方式:1.声明时赋值;2.构造方法中赋值。
final修饰类变量(常量)赋值方式:1.声明时赋值 2.在静态代码块赋值
总结:
final:此类不能被继承
四、方法调用和方法调用指令
//Java中的方法调用,分为两种
//1.静态分派(静态方法中,允许参数列表不同的重名方法,指静态方法之间的重载)
//2.动态分派(在具有继承关系的情况下,调用实例方法时,自低向上查找可用的方法版本,指实例方法的覆盖)
//java虚拟机:
//方法调用指令5个
//invokespacial 调用私有方法、构造方法
//invokeinterface 调用接口方法
//invokestatic 调用静态方法
//invokevirtual 调用虚方法(父类定义的,日后被子类覆盖的方法)
//invokedynamic 调用动态链接方法
五、idea快捷键:
alt+enter快速生成代码
alt+insert快速生成构造方法
六、idea找到.class文件的位置