一、编者的话
欢迎来到我的博客!❥(^_-)
我是VON,一个热爱JAVA的人。在这个博客上,我希望与大家分享关于java相关的一切。我相信知识的分享能够让我们共同进步,因此我会尽力提供有价值、有趣和实用的内容。
关于我(≧∇≦)ノ
我就读于大一,在编程语言方面有着丰富的学习经验。这些天来,我积累了不少关于java的见解和经验,希望能够通过博客分享给大家,也希望能够从读者那里学到更多。
博客内容(〃'▽'〃)
在这个博客中,你可以期待看到关于权限修饰符和代码块的深入分析、实用的技巧以及我的个人见解。无论你是一个新手小白还是高端大佬,这里都会有适合你的内容。
我的目标(*^▽^*)
通过这个博客,我希望能够建立一个有意义的社区,与热爱java的人们分享想法和经验。我鼓励读者们积极参与讨论,提出问题,或者分享你自己的见解和经验。我们可以共同学习,共同进步!
最后ヾ(◍°∇°◍)ノ゙
感谢你访问我的博客,希望你能够喜欢这里的内容。如果你有任何问题、建议或者想要与我交流,都可以通过博客与我取得联系。期待与你在博客中见面!
我的博客:VON
目录
default (或称为 package-private):
二、权限修饰符
Java 中的权限修饰符用于控制类、变量、方法及构造方法的访问权限。
private:
- 修饰符用于指定只有在同一个类中才可以访问该成员(变量或方法)。私有成员对于类的外部是不可见的。
示例:
public class text {
public static void main(String[] args) {
A a=new A();
System.out.println(a.name);
}
}
class A{
private String name;
public void show(){
System.out.println("show");
}
}
结果展示:
default (或称为 package-private):
- 若没有指定任何访问修饰符(即不写任何修饰符),则默认为包级私有,只能被同一个包中的其他类访问。
示例:
package com.von.day13;
public class text {
public static void main(String[] args) {
A a=new A();
System.out.println(a.name);
}
}
class A{
String name;
public void show(){
System.out.println("show");
}
}
package com.von.day13a;
import com.von.day13.*;
public class text {
public static void main(String[] args) {
A a = new A();
System.out.println(a.num);
}
}
效果展示:
protected:
- 修饰符允许同一个包中的其他类访问,同时也允许该类的子类(无论是否在同一个包中)访问。
不同包下的无关类无法使用
示例:
package com.von.day13a;
import com.von.day13.A;
public class text{
public static void main(String[] args) {
A a = new A();
System.out.println(a.name);
}
}
效果展示:
public:
- 修饰符指定该成员对任何其他类可见,无论是同一个包内的类还是不同包中的类。
示例:
package com.von.day13;
public class A{
public String name;
public void show(){
System.out.println(name);
}
}
package com.von.day13a;
import com.von.day13.A;
public class text{
public static void main(String[] args) {
A a = new A();
System.out.println(a.name);
}
}
效果展示:
三、代码块
在Java中,代码块是用来组织和执行一组语句的区域,代码块的使用可以帮助组织和控制程序的执行流程,尤其是在对象初始化、线程同步和变量作用域的管理方面非常有用。
普通代码块(或称为局部代码块):
- 普通代码块位于方法中,用花括号
{}
包围,主要用于限定变量的作用域。
示例:
package com.von.day13;
public class text {
public static void main(String[] args) {
{
int num = 0;
System.out.println(num);
}
System.out.println(num);
}
}
结果展示:
思考一下,为何无法解析符号呢?
因为变量num在{}结束后就从内存中消失了。
静态代码块:
静态代码块(Static Block)是 Java 类中的一个特殊的代码块,用于类的初始化。它在类被加载时执行,且只执行一次。静态代码块与普通的构造代码块有所不同,它使用关键字 static
来声明,并且没有参数。
静态代码块特点:
-
执行时机:静态代码块在类被加载时执行,且只执行一次,即使没有创建类的实例也会执行。类加载时机包括:当类被加载到内存中时(如通过
new
关键字创建对象、通过类名访问静态变量等情况)。 -
初始化操作:静态代码块常用于进行类的静态成员变量的初始化操作,或执行静态方法。
-
顺序和优先级:静态代码块按照其在类中的定义顺序执行,并且优先于类的构造方法执行。
静态代码块的使用场景
静态代码块通常用于以下情况:
-
静态变量初始化:如果一个类有静态变量需要初始化,可以使用静态代码块来进行初始化操作。
-
加载驱动程序:在 JDBC 中,经常使用静态代码块加载数据库驱动程序。
-
加载配置文件:如果需要在类加载时读取配置文件,可以使用静态代码块来完成这个任务。
-
静态资源加载:例如静态图片、音频等资源的加载。
注意事项
-
执行顺序:静态代码块在类加载时执行,并且只执行一次。它的执行顺序是按照在类中的定义顺序执行的。
-
异常处理:静态代码块可以包含异常处理逻辑,但如果静态代码块抛出异常,类将无法正确加载。
-
访问权限:静态代码块可以访问类的静态成员变量和静态方法,但不能访问非静态成员变量和实例方法,因为它们依赖于类的实例化。
示例:
package com.von.day13;
public class Student {
private String name;
private int age;
//静态代码块
static {
System.out.println("Hello World");
}
public Student() {
System.out.println("Hello");
}
public Student(String name, int age) {
System.out.println("World");
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package com.von.day13;
public class text {
public static void main(String[] args) {
Student s = new Student();
Student s1 = new Student("张三", 18);
}
}
效果展示:
构造代码块:
构造代码块(Constructor Block)是 Java 类中的一种特殊的代码块,它用来初始化实例对象。构造代码块在创建对象时被调用,每次创建对象时都会执行。它的特点是没有方法名,用花括号 {}
包围,只能在类中定义,不能单独存在或被调用。
构造代码块的使用场景
构造代码块通常用于以下情况:
-
初始化实例变量:在创建对象时,进行一些初始化操作,如为成员变量赋初始值。
-
提高代码的复用性:如果多个构造方法中有共同的初始化操作,可以将这部分代码放在构造代码块中,减少重复代码。
-
执行其他初始化操作:例如连接数据库、加载配置文件等操作,可以在构造代码块中进行。
注意事项
-
执行顺序:构造代码块总是在构造方法之前执行。即使是调用带参构造方法,构造代码块仍然会先于构造方法执行。
-
不支持传递参数:构造代码块不能带任何参数,也不能被显式地调用。
-
局部变量限制:在构造代码块中可以访问类的成员变量,但不能访问方法内的局部变量。
示例1:
package com.von.day13;
public class Student {
private String name;
private int age;
//构造代码块
{
System.out.println("Hello World");
}
public Student() {
System.out.println("Hello World");
}
public Student(String name, int age) {
System.out.println("Hello World");
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
结果展示:
示例2:
结果展示:
构造代码块:
- 写在成员位置的代码块
- 作用:可以把多个构造方法中重复的代码提取出来
- 执行时机:先执行构造代码块再执行构造方法
构造代码块会在对象创建时执行,每次创建对象都会执行一次。这使得它非常适合用来进行对象的初始化操作。
通过构造代码块,可以将多个构造方法中共同的初始化代码放在一起,避免重复编写。
构造代码块位于类中,紧跟在类的成员变量之后。每次创建对象时,会先执行构造代码块,然后再执行构造方法。
同步代码块:
在Java中,同步代码块是一种用于多线程编程的机制,用来确保多个线程不会同时访问共享资源而导致数据不一致或不可预料的结果。Java通过关键字 synchronized
实现同步代码块的定义,它可以应用于方法或代码块。
同步代码块的语法
同步代码块的一般语法结构如下:
synchronized (expression) {
// 需要同步的代码块
}
expression
表示一个对象表达式,通常是一个引用类型的变量或者常量,用作同步锁。- 当某个线程进入同步代码块时,它必须先获得该对象的锁,其他线程则必须等待直到该线程释放锁。
同步代码块的工作原理
-
获取锁:当线程进入同步代码块时,它尝试获取对象锁。如果锁是空闲的,那么线程将获得该锁并执行代码块。如果锁已经被其他线程持有,则该线程将被阻塞,直到获取到锁为止。
-
执行代码:一旦线程获得了对象锁,它就可以执行同步代码块中的代码。这时其他线程不能同时进入同一个对象的其他同步代码块,因为它们需要等待锁的释放。
-
释放锁:当线程执行完同步代码块中的代码后,它将释放对象锁,从而允许其他线程进入同步代码块。
使用同步代码块的示例
考虑一个简单的银行账户的例子,多个线程同时操作同一个账户的余额。为了确保操作的安全性,我们可以使用同步代码块来保护这个共享资源。
public class BankAccount {
private int balance;
public BankAccount(int initialBalance) {
this.balance = initialBalance;
}
// 存款方法
public void deposit(int amount) {
synchronized (this) { // 使用当前对象作为锁
balance += amount;
System.out.println("Deposited " + amount + ", new balance is " + balance);
}
}
// 取款方法
public void withdraw(int amount) {
synchronized (this) {
if (balance >= amount) {
balance -= amount;
System.out.println("Withdrawn " + amount + ", new balance is " + balance);
} else {
System.out.println("Insufficient funds for withdrawal");
}
}
}
public static void main(String[] args) {
BankAccount account = new BankAccount(1000);
// 创建两个线程进行存款和取款操作
Thread depositThread = new Thread(() -> {
account.deposit(500);
});
Thread withdrawThread = new Thread(() -> {
account.withdraw(200);
});
depositThread.start();
withdrawThread.start();
}
}
在上面的示例中:
deposit
和withdraw
方法使用synchronized (this)
来确保对balance
字段的操作是线程安全的。- 当一个线程调用
deposit
方法时,它会获取到BankAccount
对象的锁,执行存款操作后释放锁,这时另一个线程可以获取该锁执行取款操作,保证了账户操作的正确性和一致性。
运行结果:
同步代码块的注意事项
-
锁的选择:通常建议使用专门的对象作为锁,而不是使用
this
,因为使用this
可能导致意外的竞争条件。例如,可以创建一个私有的Object
类型的字段来作为锁对象。 -
避免死锁:死锁是多个线程因互相等待对方持有的资源而无法继续执行的情况。为避免死锁,应注意线程获取锁的顺序和持有锁的时间。
-
性能影响:使用过多的同步代码块可能会导致性能下降,因为线程可能会频繁地竞争锁。可以通过减少同步的范围或者使用并发工具类来优化性能。