javaSE——修饰符(含abstract)

1、static修饰符

1、static变量

在类中,使用static修饰的就是静态变量,其他的是非静态

建议使用静态代码块进行静态变量的初始化赋值

静态变量与非静态的区别

  • 静态变量是属于类的,可以也推荐使用类名来访问,也可以用对象访问

  • 非静态变量是属于对象的,必须使用对象来访问。

public class Student{
    private static int age;//静态
    private double score;
    public static void main(String[] args) {
        Student s = new Student();
        //推荐使用类名访问静态成员
        System.out.println(Student.age);
        System.out.println(s.age);
        //非静态只能用对象访问,尝试用类名访问编译器会报错
        System.out.println(s.score);
    }
}

  • 静态变量对于类而言在内存中只有一个,能被类的所有实例所共享。

  • 实例变量对于类的每个实例都有一份, 它们之间互不影响.

package com.kuang.oop;

public class Student {
    private static int count;//静态
    private int num;

    public Student() {
        count++;
        num++;
    }

    public static void main(String[] args) {
        Student s1 = new Student();//c=1,n=1
        Student s2 = new Student();//c=2,n=1
        Student s3 = new Student();//c=3,n=1
        Student s4 = new Student();//c=4,n=1,c公共,n各自有实例
        // 因为还是在类中,所以可以直接访问私有属性
        System.out.println(s1.num);//1
        System.out.println(s2.num);//1
        System.out.println(s3.num);//1
        System.out.println(s4.num);//1
        System.out.println(Student.count);//count静态,公共的4,下同
        System.out.println(s1.count);
        System.out.println(s2.count);
        System.out.println(s3.count);
        System.out.println(s4.count);
    }
}

2、static方法

同理,static修饰的就是静态方法,反之是非静态。

静态方法与非静态的区别

类似,静态方法属于类,“可以也推荐”用类名调用,非静态方法是属于对象的,“”必须“通过对象调用

静态方法不可以直接访问类中的非静态变量和非静态方法,但是可以直接访问类中 的静态变量和静态方法。注:this和super在类中属于非静态变量,因此静态方法不能使用

package com.kuang.oop;

public class Student {
    private static int count;
    private int num;

    public void run() {
    }

    public static void go() {
    }

    public static void test(){
    //编译通过,静态方法可以正常使用静态的东西
    System.out.println(count);
    go();
    //编译报错,静态方法里面跑非静态的东西报错
    System.out.println(num);
    run();
    }

思考:为什么静态方法和非静态方法不能直接相互访问? 加载顺序的问题!

静态方法是随着类的加载而加载的,在加载类时,程序就会为静态方法分配内存

非静态方法是属于对象的,对象是在类加载之后创建的

静态方法先于对象存在,因此在对象未存在时非静态的东西也不存在,而静态方法自然不能调用一个当时还不存在的方法。

父类的静态方法可以被子类继承,但是不能被子类重写详见https://www.cnblogs.com/bleu/p/16374463.html继承——4、方法重写

父类的非静态方法不能被子类重写为静态方法 ;

public class Person {
    //父类中的非静态方法
    public void test() {
    	System.out.println("Person");
    }
}
//编译报错
public class Student extends Person {
    //子类中欲重写为静态方法,不允许
    public static void test(){
    	System.out.println("Student");
    }
}

3、代码块和静态代码块

【类中可以编写代码块和静态代码块】

public class Person {
    {
    	//代码块(匿名代码块)
    }
    static{
    	//静态代码块
    }
}

【匿名代码块和静态代码块的执行】

因为没有名字,在程序并不能主动调用这些代码块。

  • 匿名代码块是在创建对象的时候自动执行的,并且在构造器执行之前。同时匿名代码块在每次创建对象的时候都会自动执行.

  • 静态代码块是在类加载完成之后就自动执行,并且只执行一次.

  • 注:每个类在第一次被使用的时候就会被加载,并且一般只会加载一次.

package com.kuang.oop;

public class Person {
    {
        System.out.println("匿名代码块");
    }
    static {
        System.out.println("静态代码块");
    }

    public Person() {
        System.out.println("构造器");
    }
}

public class Student extends Person{
    
}

public class Application {
    public static void main(String[] args) {
        Student s1 = new Student();
        Student s2 = new Student();
        Student s3 = new Student();

    }
}

//结果
//类第一次执行去创建对象s1
静态代码块
匿名代码块
构造器    
//s2
匿名代码块
构造器
//s3
匿名代码块
构造器

【匿名代码块和静态代码块的作用】

  • 匿名代码块:给成员变量初始化赋值,但是因为构造器也能完成这项工作,所以匿名代码块使用的并不多。
  • 静态代码块:给类中的静态成员变量初始化赋值
package com.kuang.oop;

public class Person {
    public static String name;
    static{
        name = "tom";
    }
    public Person(){
        name = "zs";//若没有构造对象,直接通过类名.的方式调用name,则此行不执行
    }
}

public class Application {
    public static void main(String[] args) {
        System.out.println(Person.name);// tom

    }
}

注:在构造器中给静态变量赋值,并不能保证能赋值成功,因为构造器是在创建对象的时候才指向,但是静 态变量可以不创建对象而直接使用类名来访问.

4、静态导入包

正常的Math.调用
package com.kuang.oop;

public class Test {
    public static void main(String[] args) {
        System.out.println(Math.random());
    }
}

静态导入包:可以直接输入包内的函数名进行调用,不需要加Math.
package com.kuang.oop;

import static java.lang.Math.random;
import static java.lang.Math.PI;;
public class Test {
    public static void main(String[] args) {
        //上面静态导入包,这里就不必写Math.random()了
        System.out.println(random());
        System.out.println(PI);
    }
}

静态导入包的好处:这种方法的好处就是可以简化一些操作,例如打印操作System.out.println(…);就可以将其写入一 个静态方 法print(…),在使用时直接print(…)就可以了。但是这种方法建议在有很多重复调用的时候使用,如果仅 有一到两次调用,不如直接写来的方便。

2、final修饰符

用final修饰的类不能被继承,没有子类。 final之后”断子绝孙”。

java中的String类被定义为final,无法用它创建子类了

【断子绝孙】

public final class Action{
}
//编译报错
public class Go extends Action{
}

用final修饰的方法可以被继承,但是不能被子类的重写。

3、abstract修饰符(抽象类)

abstract修饰符修饰方法就是抽象方法,修饰类就是抽象类

1、抽象类和抽象方法的关系

抽象类中可以包含普通的方法(非抽象方法);

但是有抽象方法的,它所在的类必须声明为抽象类

抽象类其实是对类的一个约束,相似的还有马上就要提到的接口,接口也是一种约束

二者区别:

类——extends——单继承,java里面没有多继承

接口——接口可以实现“多继承”,相当于插排,可以插多个东西

//抽象类
public abstract class Action{
    
    //抽象类让别人去做,有人帮我们实现!
	//abstract,抽象方法,只有方法的名字,没有方法的实现
	public abstract void doSomething();
}

//继承抽象类的子类(非抽象类的子类),必须实现这个抽象类的方法~ 
public class A extends Action{
    public void doSometing(){
        具体实现
    }
}

//除非~这个子类也是抽象类,就只能留给孙类了
public abstract class A extends Action{
    
}

抽象类的特点:

  1. 不能new这个抽象类,只能靠子类去实现它,是一个约束~
  2. 抽象类中可以有普通方法
  3. 抽象方法必须写在抽象类中~

接口是抽象的抽象:约束~

java面试题--抽象类存在构造器吗

存在构造器

即使你没有写任何构造函数,编译器将会为抽象类添加无参数的构造函数,没有的话你的子类将无法编译!!因为在(子)类的任何构造函数中的第一条语句隐式为super()

扩展

  1. 抽象方法的类一定是抽象类
  2. 是抽象的类不一定要有抽象方法
  3. 无法通过new实例,通过继承
  4. 子类必须实现所有的父类抽象方法,否则也要注明abstract
posted @ 2022-06-14 20:32  群青Bleu  阅读(24)  评论(0编辑  收藏  举报