Java基础——修饰符(学习分享)

修饰符

介绍

什么是修饰符

一般用来定义类、方法、变量,通常在语句的最前端。
修饰符决定了一个类、方法、变量的可使用程度。

分类

访问修饰符
非访问修饰符

访问权限修饰符

可以用来保护对类、变量、构造方法、普通方法的访问。
在这里插入图片描述

  • public(公有访问修饰符)

可以修饰类、变量、构造方法、接口、普通方法。

  • 同一包内的类之间共享。
  • 不同包之间导包后也可共享。
  • 继承关系能共享。
//public修饰类
public class TestPublic{
	public String name;//public修饰类变量
	public TestPublic(){}//public修饰构造方法
	public void test1(){}//public修饰普通方法
}
//public修饰接口
public interface TestInterface{
//抽象类是有抽象方法,也有非抽象方法。
//接口中的方法都是默认抽象的,接口其实可以理解成一种特殊的抽象类。
//接口中的成员变量默认都是public static final修饰的。所有的属性都是静态的常量。
//接口中的所有方法默认都是public abstract修饰的。
//接口没有构造方法(构造方法用于创建对象)。
	(public static final) String name = "小明";//默认public static final修饰变量
	(public abstract) void test();//默认public abstract修饰方法
}
  • protected(受保护的访问修饰符)(仅子类可见性)

可以修饰类中的变量、方法、构造方法。
不能修饰接口中的变量、方法。
不能修饰类和接口。
同包的不同类之间共享(这里的不同类指的是子类)。
不同包中的子类共享。

public class TestProtected{
	protected int age;//protected修饰成员变量(子类可见)
	protected void getAge(){}//protected修饰方法(子类可见)
	protected void TestProtected(){}//protected修饰构造方法
}
public interface TestInterface{
	//protected不能修饰接口、接口的变量、接口中的方法。
	(public static final) int age = 10;//默认public static final修饰变量
	(public abstract) void getAge();//默认public abstract修饰方法
}
  • default(默认访问修饰符)

不使用任何关键字。
可以修饰变量、方法。
同包内的类间相互可见。
接口隐式声明的变量是public static final修饰的。
接口里的方法默认情况是public修饰的。

public class TestDefault{
	int age;//修饰变量
	void getAge(){}//修饰方法
	TestDefault(){}//修饰构造方法
}
public interface TestInterface{
	(public static final) int age; //默认public static final修饰变量
	(public abstract) void getAge();//默认public abstract修饰方法
}
  • private(私有访问修饰符)

最严格的访问级别。
可以修饰类的变量、方法、构造方法。
不能修饰接口的变量和方法。
不能用来声明类和接口。
只能被当前类访问。
外部类可以通过公共的getter方法访问声明的private属性。

主要功能:

  • 隐藏类的实现细节和保护类的数据。
public class TestPrivate{
	private int age;//private修饰变量
	private TestPrivate(){}//private修饰构造方法
	private void getAge(){}//private修饰普通方法
}
public interface TestInterface{
	(public static final) int age; //默认public static final修饰变量
	(public abstract) void getAge();//默认public abstract修饰方法
}
非访问修饰符
  • static:静态的

修饰类变量、类方法。
声明独立于对象的静态变量:

  • 静态变量只有一份拷贝。
  • 也叫做类变量。
  • 可以直接使用变量名,也可以用类名+点+静态变量名的方式调用。

独立于对象的静态方法:

  • 不能使用类的非静态变量。
  • 可以直接调用静态方法名,也可以直接用类名+点+静态方法名的方式调用。
//这是一个普通类
public class TestModifierStatic {
	public String name;//非静态变量
	public static int age = 10;//静态变量(类变量)
	//静态方法,可以在未实例化对象前直接调用方法名;也可以采用TestModifierStatic.getAge()的方式调用
	public static int getAge(){
		//静态方法中不能调用非静态的变量,否则编译报错:
		//Cannot make a static reference to the non-static field TestModifierStatic.name
//		System.out.println(TestModifierStatic.name);//编译报错
		System.out.println("静态变量是:"+TestModifierStatic.age);//静态变量是:10
		System.out.println("这里是静态方法");//这里是静态方法
		return age;//可以直接使用静态变量
	}
	//非静态方法,只能在实例化对象后通过对象+点+方法名的方式调用
	public void getName(String name){
		//非静态方法中可以使用非静态变量,也可以使用静态变量
		System.out.println(name);//王二  非静态变量
		System.out.println(age);//10  静态变量
		System.out.println("这里是非静态方法");//这里是非静态方法
	}
	
	public static void main(String[] args) {
		//静态方法可以在未实例化对象前直接调用
		getAge();
		
//		getName();//编译报错:Cannot make a static reference to the non-static method getName() from the type TestModifierStatic
		//非静态方法之后在实例化之后才能调用
		TestModifierStatic tms = new TestModifierStatic();
		tms.getName("王二");
	}
}
  • abstract:抽象的

声明抽象类、抽象方法。

  • final:最终的

修饰类、方法、变量。
修饰的类不能被继承。
修饰的方法不能被重写。
修饰的变量为常量,不能被修改。
变量能被显示的初始化,并且只初始化一次。
声明的final对象的引用不能指向不同的对象,对象中的数据可以改变。
final通常和static共用声明类常量。

//final修饰的类,表示最终的类,不能被继承
public final class TestModifierFinal {}
//编译错误,final修饰的类是最终类,不能被继承
//The type TestMain cannot subclass the final class TestModifierFinal
public class TestMain extends TestModifierFinal{}
//final修饰的变量为常量,要初始化
//public final String name;//final修饰的变量需要初始化,否则编译错误:The blank final field name may not have been initialized
public final String name = "李二";//final修饰变量为常量,要初始化
//final修饰的方法不能被重写
public  class TestModifierFinal {
	public final String name = "李二";//final修饰变量为常量,要初始化
	public final static int age = 10;//final 组合static声明类常量
	//final修饰的方法,表示最终方法,不能被重写
	public final void getName(){
		System.out.println(name);//李二
		System.out.println(age);//10
		System.out.println("final修饰的方法");//final修饰的方法
	}
	//普通方法
	public void getAge(){
		System.out.println(name);//李二
		System.out.println(age);//10
		System.out.println("普通方法");//普通方法
	}
	public static void main(String[] args) {
		TestModifierFinal tmf = new TestModifierFinal();
		tmf.getName();
		tmf.getAge();
		/*运行结果为:
		李二
		10
		final修饰的方法
		李二
		10
		普通方法*/
	}
}
public class TestMain extends TestModifierFinal{
	//final修饰的父类方法不能被重写
	//编译错误:Cannot override the final method from TestModifierFinal
//	public void getName(){}
	public void getAge(){
		System.out.println("子类重写父类方法");//子类重写父类方法
	}
	public static void main(String[] args) {
		TestModifierFinal tmf = new TestMain();
		tmf.getAge();
		tmf.getName();//子类不能重写父类的final方法,但是可以调用
		/*运行结果为:
		子类重写父类方法
		李二
		10
		final修饰的方法*/
	}
}
  • synchronized:

是一种同步锁。
声明的方法同一时间只能被一个线程访问。

  • 修饰代码块:被修饰的代码块被称作同步语句块;作用范围时{}内;作用对象是调用同步语句块的对象。
  • 修饰方法:被修饰的方法称为同步方法;作用范围是整个方法;作用对象是调用这个方法的对象。
  • 修饰静态方法:被修饰的静态方法叫做静态同步方法;作用范围是整个静态方法;作用对象是整个类的所有对象。
  • 修饰类:作用范围是整个类;作用对象是整个类中的所有对象。
  • synchronized修饰代码块
public class TestModifierSynchronized implements Runnable{
	private static int count;//声明一个全局变量  计数器
	//声明构造方法
	public TestModifierSynchronized() {
        count = 0;
    }
	//重写run()方法
	@Override
	public void run() {
		// TODO Auto-generated method stub
		synchronized (this) {
			for (int i = 0; i < 5; i++) {
				try {
					System.out.println("线程名:"+Thread.currentThread().getName()+":"+(count++));
					Thread.sleep(100);//相邻两个线程休眠100毫秒
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}
	public int getCount(){
		return count;
	}
}
public static void main(String[] args) {
	//方式一:同时访问一个对象
	TestModifierSynchronized tms1 = new TestModifierSynchronized();
	Thread t1 = new Thread(tms1,"sync_thread-1");
	Thread t2 = new Thread(tms1,"sync_thread-2");
	t1.start();
	t2.start();
	/*运行结果为:
	线程名:sync_thread-1:0
	线程名:sync_thread-1:1
	线程名:sync_thread-1:2
	线程名:sync_thread-1:3
	线程名:sync_thread-1:4
	线程名:sync_thread-2:5
	线程名:sync_thread-2:6
	线程名:sync_thread-2:7
	线程名:sync_thread-2:8
	线程名:sync_thread-2:9*/
	
	/*总结:两个并发线程访问同一个对象中的synchronized代码,同一时刻只有一个线程执行;
	另一个线程阻塞,等当前线程执行完毕整个代码块,另一个线程才能执行该代码块。这两个线程
	是互斥的,执行synchronized代码块时锁定了当前对象,执行完代码块才能释放对象所,下
	一个线程才能获取对象所并执行。*/

	//方式二:同时访问多个对象
	TestModifierSynchronized tms2 = new TestModifierSynchronized(); 
	TestModifierSynchronized tms3 = new TestModifierSynchronized(); 
	Thread t3 = new Thread(tms2,"sync_thread-3");
	Thread t4 = new Thread(tms3,"sync_thread-4");
	t3.start();
	t4.start();
	/*运行结果为:
	线程名:sync_thread-3:1
	线程名:sync_thread-4:0
	线程名:sync_thread-3:3
	线程名:sync_thread-4:2
	线程名:sync_thread-4:4
	线程名:sync_thread-3:5
	线程名:sync_thread-3:7
	线程名:sync_thread-4:6
	线程名:sync_thread-3:8
	线程名:sync_thread-4:9*/
	
	/*总结:因为是两个线程分别创意一个对象去执行的,所以说每个线程都是锁定了自己创建的对象,
	他们相互之间没有联系。*/
}
  • synchronized修饰普通方法
public class TestModifierSynchronized2 implements Runnable{
	private static int count = 0;//全局变量  计数器
	//synchronized修饰普通方法
	public synchronized void testRun(){
		for (int i = 0; i < 5; i++) {
			try {
				System.out.println("线程名 :" + Thread.currentThread().getName() + " 当前计数器 :" + (count++));
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	//重写run方法
	@Override
	public void run() {
		testRun();
	}
}
public static void main(String[] args){
	TestModifierSynchronized2 tms21 = new TestModifierSynchronized2();
	Thread t5 = new Thread(tms21,"sync_thraf-5");
	Thread t6 = new Thread(tms21,"sync_thraf-6");
	t5.start();
	t6.start();
	/*运行结果为:
	线程名 :sync_thraf-5 当前计数器 :0
	线程名 :sync_thraf-5 当前计数器 :1
	线程名 :sync_thraf-5 当前计数器 :2
	线程名 :sync_thraf-5 当前计数器 :3
	线程名 :sync_thraf-5 当前计数器 :4
	线程名 :sync_thraf-6 当前计数器 :5
	线程名 :sync_thraf-6 当前计数器 :6
	线程名 :sync_thraf-6 当前计数器 :7
	线程名 :sync_thraf-6 当前计数器 :8
	线程名 :sync_thraf-6 当前计数器 :9*/
	
	/*总结:synchronized修饰普通方法时的效果和修饰代码块的效果是一样的。*/
	
	TestModifierSynchronized2 tms22 = new TestModifierSynchronized2();
	TestModifierSynchronized2 tms23 = new TestModifierSynchronized2();
	Thread t7 = new Thread(tms22,"sync_thrad-7");
	Thread t8 = new Thread(tms23,"sync_thrad-8");
	t7.start();
	t8.start();
	/*运行结果为:
	线程名 :sync_thrad-7 当前计数器 :1
	线程名 :sync_thrad-8 当前计数器 :0
	线程名 :sync_thrad-7 当前计数器 :2
	线程名 :sync_thrad-8 当前计数器 :3
	线程名 :sync_thrad-8 当前计数器 :4
	线程名 :sync_thrad-7 当前计数器 :5
	线程名 :sync_thrad-8 当前计数器 :6
	线程名 :sync_thrad-7 当前计数器 :7
	线程名 :sync_thrad-7 当前计数器 :8
	线程名 :sync_thrad-8 当前计数器 :9*/
	
	/*总结:synchronized修饰普通方法时的效果和修饰代码块的效果是一样的。*/
}
  • synchronized修饰静态方法
public class TestModifierSynchronized3 implements Runnable{
	private static int count = 0;//全局变量  计数器
	//重写run方法
	@Override
	public void run() {
		testRun();
	}
	//synchronized修饰静态方法
	public synchronized static void testRun(){
		for (int i = 0; i < 5; i++) {
			try {
				System.out.println("线程名:"+Thread.currentThread().getName()+" 当前计数器:"+(count++));
				Thread.sleep(1000);//睡眠时间
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}
public static void main(String[] args){
	TestModifierSynchronized3 tms31 = new TestModifierSynchronized3();
	Thread t9 = new Thread(tms31,"sync_thread-9");
	Thread t10 = new Thread(tms31,"sync_thread-10");
	t9.start();
	t10.start();
	/*运行结果为:
	线程名:sync_thread-9 当前计数器:0
	线程名:sync_thread-9 当前计数器:1
	线程名:sync_thread-9 当前计数器:2
	线程名:sync_thread-9 当前计数器:3
	线程名:sync_thread-9 当前计数器:4
	线程名:sync_thread-10 当前计数器:5
	线程名:sync_thread-10 当前计数器:6
	线程名:sync_thread-10 当前计数器:7
	线程名:sync_thread-10 当前计数器:8
	线程名:sync_thread-10 当前计数器:9*/
	
	/*总结:因为调用了静态方法,静态方法属于类,只在加载类的时候执行一次,所以多个线程并发执行的时候
	会竞争同一个对象的锁。*/
	
	TestModifierSynchronized3 tms32 = new TestModifierSynchronized3();
	TestModifierSynchronized3 tms33 = new TestModifierSynchronized3();
	Thread t11 = new Thread(tms32,"sync_thread-11");
	Thread t12 = new Thread(tms33,"sync_thread-12");
	t11.start();
	t12.start();
	/*运行结果为:
	线程名:sync_thread-11 当前计数器:0
	线程名:sync_thread-11 当前计数器:1
	线程名:sync_thread-11 当前计数器:2
	线程名:sync_thread-11 当前计数器:3
	线程名:sync_thread-11 当前计数器:4
	线程名:sync_thread-12 当前计数器:5
	线程名:sync_thread-12 当前计数器:6
	线程名:sync_thread-12 当前计数器:7
	线程名:sync_thread-12 当前计数器:8
	线程名:sync_thread-12 当前计数器:9*/
	
	/*总结:因为调用了静态方法,静态方法属于类,只在加载类的时候执行一次,所以多个线程并发执行的时候
		会竞争同一个对象的锁。*/
}
  • synchronized修饰类
public class TestModifierSynchronized4 implements Runnable{
	private static int count;
	//构造方法
	public TestModifierSynchronized4() {
		count = 0;
	}
	//重写方法
	@Override
	public void run() {
		testRun();
	}
	//synchronized修饰类
	public void testRun(){
		synchronized (TestModifierSynchronized4.class) {
			for (int i = 0; i < 5; i++) {
				try {
					System.out.println("线程名:"+Thread.currentThread().getName()+" 计数器:"+(count++));
					Thread.sleep(1000);//设置休眠时间
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}
}
public static void main(String[] args){
	TestModifierSynchronized4 tms41 = new TestModifierSynchronized4();
	Thread t13 = new Thread(tms41,"sync_thrad-13");
	Thread t14 = new Thread(tms41,"sync_thrad-14");
	t13.start();
	t14.start();
	/*运行结果为:
	线程名:sync_thrad-13 计数器:0
	线程名:sync_thrad-13 计数器:1
	线程名:sync_thrad-13 计数器:2
	线程名:sync_thrad-13 计数器:3
	线程名:sync_thrad-13 计数器:4
	线程名:sync_thrad-14 计数器:5
	线程名:sync_thrad-14 计数器:6
	线程名:sync_thrad-14 计数器:7
	线程名:sync_thrad-14 计数器:8
	线程名:sync_thrad-14 计数器:9*/
	
	/*总结:synchronized修饰类,给整个类加锁,所有的对象用同一把锁。*/
	
	TestModifierSynchronized4 tms42 = new TestModifierSynchronized4();
	TestModifierSynchronized4 tms43 = new TestModifierSynchronized4();
	Thread t15 = new Thread(tms42,"sync_thrad-15");
	Thread t16 = new Thread(tms43,"sync_thrad-16");
	t15.start();
	t16.start();
	/*运行结果为:
	线程名:sync_thrad-15 计数器:0
	线程名:sync_thrad-15 计数器:1
	线程名:sync_thrad-15 计数器:2
	线程名:sync_thrad-15 计数器:3
	线程名:sync_thrad-15 计数器:4
	线程名:sync_thrad-16 计数器:5
	线程名:sync_thrad-16 计数器:6
	线程名:sync_thrad-16 计数器:7
	线程名:sync_thrad-16 计数器:8
	线程名:sync_thrad-16 计数器:9*/
	
	/*总结:synchronized修饰类,给整个类加锁,所有的对象用同一把锁。*/
}
  • volatile:

只能修饰变量。
修饰的成员变量每次被线程访问时,都会从内存中重读该成员变量的最新值。
当成员变量发生变化时,强迫线程将变化值回写到共享内存中。

private volatile static int num = 0;

参考地址:
https://blog.csdn.net/u012723673/article/details/80613557
https://www.jb51.net/article/100962.htm
https://blog.csdn.net/qq_38011415/article/details/89047812

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值