Java基础-修饰符的使用

权限修饰符

java关于访问权限的修饰符有4个,分别为private、缺省、protected 和 public

修饰符访问权限
private私有的,只能在本类中访问
缺省缺省,不加任何修饰符时,只能同一个包内访问
protected受保护的,同一个包内或子类允许访问
public公共的,项目内都可以访问

private

  • 私有的,可以修饰属性、方法、构造方法,内部类,需要注意的是private不能修
    饰类本身
    ,因为这会导致其它类访问不到该类,那么该类的存在就没有意义了。
  • 修饰属性:通常一个类会将属性私有化,而对外提供公开的方法来访问私有的属性
  • 修饰方法:被修饰的方法应该是类专属的,不需要其他类访问的方法。
  • 修饰构造方法:防止其他类实例化该类,需要注意的是如果一个类只有私有化构造方法,那么该类也无法被继承,常见的用法有单例模式、工具类等
  • 修饰内部类:被private修饰的内部类只有外部类和内部类能实例化。
package test;

public class PrivateTest {
    // 私有化属性,而对外提供公共的方法
    private int field = 0;
    public int getFiled() {
        return field;
    }

    // 私有方法
    private void privateMethod() {
        System.out.println("我是私有方法,只有本类的方法才能调用我");
    }

    //私有化构造方法,只有本类能实例化,以下为实现单例模式方法之一
    private Test() {}
    private static Test newInstance = new Test();
    public static Test getNewInstance() {
        return newInstance;
    }


    // 私有化内部类,只有本类和内部类可以实例化内部类
    private InnerClass innerClass = new InnerClass();
    private class InnerClass{
        InnerClass innerClass = new InnerClass();
    }
}

缺省

如果一个类、类的属性或者方法只想本包中的其他类访问,那么就可以缺省权限修饰符

package test;
/**
 * 只有本包的类能访问我,继承我
 */
class DefaultTest {

    int defaultfield = 0;

    void defaultMethod() {
        System.out.println("你好,我是test包下的类");
    }

    //同包才能实例化我
    DefaultTest() {}
    
    // 同包可以实例化内部类
    class InnerClass{
        InnerClass(){
            System.out.println("hello");
        }
    }
}
package test;

/**
 * 我也是test包下的类哟
 */
public class MainTest {
    public static void main(String[] args) {
        // 访问同包的类
        DefaultTest defaultTest = new DefaultTest();
        // 访问同包的属性
        int field = defaultTest.defaultfield;
        // 访问同包的方法
        defaultTest.defaultMethod();
        // 访问同包的内部类
        DefaultTest.InnerClass innerClass = defaultTest.new InnerClass();
    }

    // 继承同包下的类
    class SubDefaultClass extends DefaultTest{

    }
}

protected

如果一个类中的属性、方法等除了本包中能访问外,还想外包的子类访问,那么就可以用protected修饰,需要注意的是protected不能修饰类本身,因为protected修饰符是想外包中的子类能够访问,如果protected修饰类的话,那么外包就无法访问到该类,也就没办法继承该类了。

public

public修饰的属性、方法、类可以在本项目中任何地方访问,但是,public修饰的属性通常是不安全的,因为任何类都可以修改属性的值。通常的,我们也应该尽可能的使访问权限最小化,即如果一个属性或方法等可以用private修饰,那么就不要用缺省甚至更大权限来修饰它,保证其最小可见性。

特征修饰符

static

  • static可以修饰类的属性、方法、匿名方法(代码块)和内部类,不能修饰构造方法和类本身,被static修饰属性、方法等不需要在对象初始化之后才能使用,调用它们的方式是使用 类名.属性/类名.方法等来使用它们。
  • 静态属性:被static修饰的属性是静态属性,用例:定义一个静态属性来统计网址访问次数
  • 静态方法:被static修饰的普通方法是静态方法,用例:工具类的方法,用静态方法代替构造方法来实例化对象
  • 静态代码块:被static修饰的匿名方法是静态代码块
  • 静态内部类:被static修饰的内部类是静态内部类

final

  • final修饰符可以修饰属性、方法、类,不能修饰代码块、构造方法。
  • final修饰属性:被final修饰的属性,它的的引用不能改变,即该属性只能被赋值一次,不能重新赋值,但是,如果该属性指向的是一个对象/数组,那么对象/数组本身的属性/值是可以改变的。另外,如果一个属性同时被static和final修饰,那么可以将该属性当做常量看待。
package test;

public class FinalTest {
    /**
     * final修饰的属性
     */
    private final int[] a = new int[10];

    /**
     * 可以修改数组的值
     */
    private void modify() {
        a[0] = 1;
    }

    /**
     * 不能被重新赋值
     */
    private void assign() {
        // 赋值语句会报错,这里只是演示
        a = new int[10];
    }
}
  • final修饰方法:被final修饰的方法不能被子类重写,如果设计的方法不想被重写,那么该方法应该用final修饰。
  • final修饰类:被final修饰的类不能被继承,该类是不可变的,比如:String、Integer等等

abstract

  • abstract 可以修饰类和普通方法,不能修饰构造方法,不能和static、final同时修饰方法
  • abstract修饰类:被abstract修饰的类叫做抽象类,抽象类有构造方法用于被子类继承时使用,但是抽象类本身不能被实例化;抽象类可以有但不必须有抽象方法,但是有抽象方法的类必须是抽象类。
  • abstract修饰方法:被abstract修饰的方法叫做抽象方法,抽象方法只有方法访问权限、返回值、方法名和所需参数,没有具体的实现,方法具体的实现由子类重写。之所以不能和static、final同时修饰方法是因为static修饰的方法在类加载的时候被加载,不需要对象的实例化,而final修饰的方法不能被重写。
package test;

/**
 * 被abstract修饰的类是抽象类
 */
public abstract class AbstractTest {
    /**
     * 抽象方法,没有方法的具体实现,不能同时被static或final修饰
     */
    public abstract void abstractMethod();

    public static void main(String[] args) {
        // 不能实例化抽象类,编译会报错,此处只是演示
        new AbstractTest();
    }
}

volatile

volatile用于修饰属性,它想表达的意思是该属性需要从原始地址取值,而不是寄存器中获取,关于计算机方面的知识这里不做过多介绍,这里举个例子来说明一下:
假设在一个箱子里有10个苹果,有A、B两个人来查看箱子中苹果的数量,如果没有volatile修饰,那么A、B两个人在查看完数量后就记住了有10个苹果,当其中一个人偷吃了一个苹果,那么另一个人依然以为有10个苹果,并告诉别还有10个苹果,如果有volatile修饰,那么,每当有人问箱子里还有几个苹果时,A、B都必须跑到箱子处重新数一下苹果的数量,然后告诉别人剩余的数量。

package test;

import java.util.concurrent.TimeUnit;

public class VolatileTest {
    /**
     * 箱子中苹果的数量
     * 当没有volatile修饰时,程序进入了死循环,因为线程A无法知道有没有人偷吃了苹果
     * 当有volatile修饰时,线程A在1秒后打印了有人吃了苹果
     */
    // private static int appleNum = 10;
    private static abstract int appleNum = 10;

    public static void main(String[] args) {
        // 线程A查看苹果数量
        new Thread(() -> {
            // 如果数量发生变化,证明有人吃了苹果
            while (appleNum==10) {}
            System.out.println("有人吃了苹果");
        },"A").start();

        // 线程B偷吃了一个苹果
        new Thread(() -> {
            // 这里睡1秒是为了保障线程A先去查看了苹果的数量,然后线程B再去偷吃
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {}
            
            // 偷吃了一个苹果,数量-1
            appleNum -= 1;
        },"B").start();
    }
}

transient

transient用作修饰属性,被修饰的属性在对象的序列化时忽略序列化,可以用在一些私密的属性上,使其忽略序列化,比如用户的密码等。

package test;

import java.io.*;

/**
 * 实现Serializable 才能序列化对象
 */
public class TransientTest implements Serializable {
    /**
     * 用户名,可以序列化
     */
    private String username = "张三";
    
    /**
     * 密码,不能序列化
     */
    private transient String password = "123456";

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // 序列化
        TransientTest transientTest = new TransientTest();
        byte[] bytes;
        try(ByteArrayOutputStream os = new ByteArrayOutputStream()) {
            ObjectOutputStream oos = new ObjectOutputStream(os);
            oos.writeObject(transientTest);
            bytes = os.toByteArray();
        }

        // 反序列化
        try(ByteArrayInputStream is = new ByteArrayInputStream(bytes)) {
            ObjectInputStream ois = new ObjectInputStream(is);
            Object object = ois.readObject();
            System.out.println(object);
        }
    }

    @Override
    public String toString() {
        return "TransientTest{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

运行结果:没有transient 修饰的username属性可以正常序列号和反序列化,而password属性打印为null

native

native用作修饰方法,该方法为本地方法,不是java语言实现的,很多java基础包中的类用到此修饰符,项目开发基本用不到,作为了解即可。

以上为个人对java知识的理解和认知,希望和大家共同学习,共同进步,有什么理解错误的地方希望大家指出并多多包涵,希望和大家一起交流、探讨和学习。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值