Should ordinary Java class member variables be private or public?

This article uses Q&A to think about whether ordinary Java class member variables should be modified with public static or private static. If you have different opinions, please write them in the comment area, which will help me learn more.

Premise of this article:

  • Use static modification for Java class member variables, and then discuss whether to use private or public 
  • If the class is annotated with @Configuration and used in conjunction with @Value to inject values, @Value cannot assign values ​​to statically modified variables such as private static int age . Instead, ordinary setter methods should be used.

Question discussion:

Q1: In Java, is it better to modify class member variables with public static or private static?

In Java, for class member variables, there are applicable scenarios for using public staticmodification and decoration, and there is no absolute good or bad. private staticIt mainly depends on your needs and design.

1.public staticModification:

  • advantage:
    • This variable can be accessed from anywhere without creating an instance of the class.
    • This variable can be modified directly outside the class.
  • shortcoming:
    • Encapsulation is broken because other classes can directly modify this variable.
    • May cause multi-threading issues because this variable can be modified anywhere.

2.private staticModification:

  • advantage:
    • Encapsulation is good because other classes cannot directly access this variable.
    • This variable can be prevented from being modified in other classes, thereby improving code security.
  • shortcoming:
    • This variable cannot be accessed or modified directly outside the class, it must be accessed and modified through the class method.

In general, if you want other classes to be able to access and modify this variable, then use public staticmodification; if you want other classes not to be able to access and modify this variable, then use private staticmodification.

Q2: The principle of using the set method in Java to modify member variables modified by private static

In Java, the principle of using setmethods to modify private staticmodified member variables mainly involves Java's access modifiers and the characteristics of static member variables. Here are some key points:

1. Access modifier : In Java, privatemodifier indicates that a member variable can only be accessed in the class in which it is located. This means that other classes cannot directly access and modify this privatemember variable.

2. Static member variables : When a member variable is staticmodified, the member variable no longer belongs to any specific object instance, but to the class itself. Therefore, you can directly access this static member variable through the class name without creating an instance of the class first.

However, although member variables cannot be directly accessed and modified from outside the class, a static method private staticcan be provided inside the class to modify this member variable. This is called method.publicprivate staticset

For example:

public class MyClass {
    private static int myVariable;

    public static void setMyVariable(int newValue) {
        myVariable = newValue;
    }
}

In this example, we provide a setmethod (here setMyVariable) to modify myVariablethe value. Although this method uses publicmodifiers, because it is static, it cannot be accessed from outside the class. It can only be accessed from within the class or from other static methods of this class. So even if you set a variable to , you can still modify it private staticby providing a static method in the class .public

However, a potential problem with doing this is that any other code that has access to this class can setmodify the value by calling this method myVariable, which may lead to unexpected behavior. Therefore, the possible impacts of this technology need to be carefully considered when using it.

Q3: What if the setMyVariable() method is replaced with a non-static one?

If you setMyVariable()change a method from static to non-static, then the method no longer belongs to the class itself, but to every instance of the class. In this case, you can call this method by creating an object of the class, modifying myVariablethe value.

Here is setMyVariable()an example of changing a method from static to non-static:

public class MyClass {
    private static int myVariable;

    public void setMyVariable(int newValue) {
        myVariable = newValue;
    }
}

Using non-static methods to modify static member variables may cause some problems. Because static member variables belong to the class itself, while non-static methods belong to instances of the class. When a non-static method modifies a static member variable, each object instance modifies the same static variable, which can lead to unpredictable behavior.

Therefore, if you want each object instance to have its own copy of the variable value, you can make the member variable non-static and provide a static method for modifying the variable. In this way, each object instance can modify its own copy of the variable value through static methods.

Q4: What specific problems may result from using non-static methods to modify static member variables?

Using non-static methods to modify static member variables may cause the following problems:

  • Destroy encapsulation. Because other classes can directly access this static member variable, they can modify this static member variable by creating an instance of the class and calling non-static methods.
  • May cause multi-threading issues. Because you can call non-static methods to modify this static member variable by creating an instance of the class at any time, thread safety issues may arise in a multi-threaded environment.

If you do not want to destroy encapsulation and want to modify static member variables outside the class, you can consider using the static methods provided by the class to make modifications.

Q5: Code examples that cause threading issues

Below is an example of code that may cause threading issues.

public class SharedResource {
    private int count = 0;

    public void incrementCount() {
        count++;
    }

    public int getCount() {
        return count;
    }
}

public class Main {
    public static void main(String[] args) {
        SharedResource resource = new SharedResource();

        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 100000; i++) {
                resource.incrementCount();
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 100000; i++) {
                resource.incrementCount();
            }
        });

        thread1.start();
        thread2.start();

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Count: " + resource.getCount());
    }
}

This program creates two threads, each of which   increments SharedResource the object's  properties 100,000 times. countBecause these two threads are executed in parallel, thread safety issues may occur during execution, resulting in the final  count value being less than 200,000 (expected value).

To solve this problem,  synchronized keywords can be used to ensure that only one thread can access  incrementCount() the method at any time. Or use  java.util.concurrent.atomic the atomic classes in the package (such as  AtomicInteger), which provide thread-safe operations.

Q6: Example code that uses non-static methods to modify static member variables resulting in thread safety

The following is an example of Java code that uses non-static methods to modify static member variables but leads to thread unsafeness:

public class SharedData {
    private static int count = 0;

    public void incrementCount() {
        synchronized(this) {
            count++;
        }
    }

    public static int getCount() {
        return count;
    }
}

public class Main {
    public static void main(String[] args) {
        SharedData sharedData = new SharedData();

        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 100000; i++) {
                sharedData.incrementCount();
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 100000; i++) {
                sharedData.incrementCount();
            }
        });

        thread1.start();
        thread2.start();

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Count: " + SharedData.getCount());
    }
}

This code attempts  to ensure thread safety by  synchronously accessing static member variables  incrementCount() using methods  . However, this approach is incorrect because   only an object instance is locked, not a static member variable  . Synchronization is not guaranteed between multiple calls to the same object instance in multiple threads.synchronized(this)countthiscount

To properly synchronize access to static member variables, you should use the class as a lock, ie  synchronized(SharedData.class).

Q7: What are the disadvantages of using the synchronized keyword to make the entire class a lock?

Using synchronizedkeywords to lock an entire class is certainly possible, but it has some potential drawbacks. Here are some possible issues:

1. No fine-grained control : Synchronization on the entire class means that any thread needs to obtain this lock when accessing any instance of the class. This may prevent concurrent access to different instances of the same class, but may not be ideal for concurrent access to different parts of the same instance.

2. The lock is held for too long : Since the lock is held on the entire class, the lock may be held for too long, reducing the available threads and potentially causing a performance bottleneck. This particularly causes problems with long-lived objects, such as singletons or static instances.

3. Unfair lock : If a class lock is used, the thread waiting the longest may not get the lock first, because the class lock is unfair. This may cause some threads to wait for a long time, while other threads can obtain the lock immediately.

4. State inconsistency : Synchronization across the entire class means that all threads need to obtain the same lock when performing any operation that modifies the shared state. This can lead to state inconsistencies, especially if an exception occurs while the thread is holding the lock.

5. Not easy to understand and debug : Synchronizing on the entire class may make the logic of the code unclear, because any thread that changes this class may affect other threads. This makes understanding and debugging multi-threaded code more difficult.

To solve these problems, it is often recommended to use locks on specific methods or blocks of code that need to be synchronized, rather than using locks on the entire class. This enables finer-grained control, reduces lock holding time, enables fair locking, maintains state consistency, and makes code easier to understand and debug.

Guess you like

Origin blog.csdn.net/baidu_38493460/article/details/132799784