Types of data members

  • Last Updated: July 26, 2023
  • By: javahandson
  • Series
img

Types of data members

Learn how data members in Java work: instance versus static fields, memory, default values, initializer blocks, access modifiers, and the mistakes beginners keep making.

1. Introduction

Data members in Java are the variables you declare inside a class. They hold the state of your objects, and they come in exactly two flavours.

Picture a school. Every student has a roll number and a name, and those differ from student to student. But the school name is the same for all of them.

That is the whole idea in one sentence. Some values belong to each object, and some belong to the class as a whole.

Java calls the first kind instance data members. It calls the second kind static data members. Get this split right, and a surprising number of bugs simply never happen.

1.1 What This Article Covers

We will build this up slowly, with plenty of small examples. Here is the plan:

  • What a data member is, and how it differs from a local variable
  • Instance members: one copy per object, and why that matters
  • Static members: one shared copy, created when the class loads
  • Default values, and which variables actually get them
  • Static blocks and instance blocks, plus the exact order they run in
  • Access modifiers, and why private is almost always right
  • When static helps you, and when it quietly hurts you
  • Common mistakes, and the interview questions that follow

If you have written a simple class before, you already know enough to follow along.

2. What Is a Data Member?

2.1 Fields, Not Local Variables

A data member is a variable declared directly inside a class, outside every method. Java developers usually just call them fields.

public class Student {

    int rollNumber;    // data member (field)
    String name;       // data member (field)

    void study() {
        String subject = "Java";   // NOT a data member, it is local
    }
}

Notice subject sits inside a method. That makes it a local variable, and it disappears the moment study() finishes.

The two fields above behave very differently. They stick around for as long as the object does.

2.2 The Two Kinds

Java splits data members into exactly two groups:

  • Instance data members, also called non-static members. Every object gets its own copy.
  • Static data members, also called class-level members. One copy exists, and every object shares it.

The only visible difference is one keyword. Add static, and the behaviour flips completely.

3. Instance Data Members

3.1 One Copy Per Object

Declare a field without static, and you get an instance member. Each object you create carries its own private copy.

public class Student {

    int studentId;
    String name;

    public static void main(String[] args) {

        Student student1 = new Student();   // gets its own memory
        student1.studentId = 101;
        student1.name = "Rohit";

        Student student2 = new Student();   // gets separate memory
        student2.studentId = 102;
        student2.name = "Virat";

        System.out.println(student1.studentId); // Output: 101
        System.out.println(student2.studentId); // Output: 102
    }
}

Change student1 and student2 never notices. Two objects, two separate boxes, no interference.

3.2 Memory Arrives With the Object

Writing the class reserves nothing. A class is only a blueprint, and blueprints do not take up space.

Memory shows up the moment you call new. That is when the JVM carves out room on the heap for the fields.

Create ten Student objects, and you get ten separate studentId boxes. Create none, and you get zero.

3.3 They Get Default Values

Here is a genuine convenience. Instance members never sit empty, because Java fills them in for you.

  • Whole numbers like int and long start at 0
  • Decimals like float and double start at 0.0
  • boolean starts as false
  • char starts as the null character
  • Objects, including String, start as null
public class Student {

    int studentId;      // becomes 0
    String name;        // becomes null
    boolean active;     // becomes false

    public static void main(String[] args) {
        Student s = new Student();
        System.out.println(s.studentId); // Output: 0
        System.out.println(s.name);      // Output: null
        System.out.println(s.active);    // Output: false
    }
}

Local variables get no such treatment. Read one before assigning it, and the compiler refuses to build your code.

3.4 The Static Context Trap

This error catches almost every beginner. You cannot touch an instance field directly from main.

public class Student {

    String name;

    public static void main(String[] args) {
        // name = "Virat";
        // error: non-static variable name cannot be referenced
        //        from a static context
    }
}

Think about why. The main method is static, so it runs before any object exists.

Java has a fair question for you. Which student’s name did you mean, when no student has been created yet?

The fix is simple. Make an object first, then go through it.

public static void main(String[] args) {
    Student student = new Student();
    student.name = "Virat";              // works, we have an object now
    System.out.println(student.name);    // Output: Virat
}

4. Static Data Members

4.1 One Copy Per Class

Put static in front of a field, and the rules change entirely. Now only one copy exists, no matter how many objects you build.

public class Student {

    static String schoolName = "Java High";  // one copy, shared
    String name;                             // one copy per object
}

Every Student shares that single schoolName box. They each keep their own name.

4.2 Memory Arrives With the Class

A static field does not wait for new. The JVM sets aside its memory when the class first loads.

The classloader pulls the bytecode from disk into memory, and static fields come alive right then. No object required.

That timing explains a lot. It is exactly why you can reach a static field before creating a single object.

4.3 Changes Are Visible Everywhere

Since everyone shares one box, a change through one object shows up in all of them.

public class Student {

    static int studentId;   // shared by every object
    String name;

    public static void main(String[] args) {

        Student student1 = new Student();
        student1.studentId = 101;
        student1.name = "Rohit";

        Student student2 = new Student();
        student2.name = "Virat";        // we never set studentId here

        System.out.println(student1.studentId); // Output: 101
        System.out.println(student2.studentId); // Output: 101
    }
}

Look at that last line closely. We never assigned studentId through student2, yet it prints 101.

This is the power of static, and also the danger. A roll number should never be shared, so that field has no business being static.

4.4 Use the Class Name

Reaching a static field through an object works, but it reads badly. It hints that the value belongs to that object, which is a lie.

Go through the class name instead. The intent becomes obvious.

Student.studentId = 101;              // clear: this belongs to the class
System.out.println(Student.studentId); // Output: 101

Most IDEs will even warn you when you access a static member through an instance. Listen to that warning.

4.5 A Real Use: Counting Objects

Here is where static genuinely shines. Suppose you want to know how many Student objects have been created.

A shared counter solves it perfectly, because the count belongs to the class and not to any one student.

public class Student {

    static int count = 0;   // shared across all objects
    String name;

    public Student(String name) {
        this.name = name;
        count++;            // every new object bumps the same counter
    }

    public static void main(String[] args) {
        new Student("Rohit");
        new Student("Virat");
        new Student("Dhoni");

        System.out.println(Student.count); // Output: 3
    }
}

Try that with an instance field and it breaks immediately. Each object would start its own counter at zero.

5. Instance vs Static: Side by Side

Keep this table handy. It answers most questions people have about data members in Java.

Aspect Instance member Static member
Keyword None static
How many copies One per object One per class
Memory allocated When you call new When the class loads
Lives in The heap, with the object The method area
Best access Through an object Through the class name
Reachable from main Only via an object Directly
Gets a default value Yes Yes
Good for Data that differs per object Data shared by everything

If you memorise one row, pick the second. Everything else follows from it.

5.1 Where Each One Lives in Memory

The JVM splits memory into regions, and your variables land in different ones. Knowing which is which explains most of their behaviour.

  • The heap holds objects. Instance members live inside the object, right there on the heap.
  • The method area holds class-level information. Static members live here, alongside the bytecode.
  • The stack holds method calls. Local variables live in the frame for the current call.

Now the lifetimes make sense. A stack frame disappears when the method returns, so local variables vanish with it.

An object survives on the heap until nothing references it. Then the garbage collector reclaims it, and its instance members go too.

Static members outlive everything. They stay in the method area for as long as the class stays loaded, which is usually the whole program.

5.2 A Quick Mental Model

Picture a company. Each employee has a desk with their own nameplate, and that is an instance member on the heap.

The company logo hangs once in reception. Everyone shares it, and it belongs to the company rather than to any employee. That is a static member.

A scribbled note on a whiteboard during one meeting is a local variable. When the meeting ends, somebody wipes the board.

6. Initializer Blocks

Sometimes a plain value is not enough to set up a field. Maybe you need a loop, or a try-catch. Java gives you initializer blocks for exactly that.

6.1 The Static Block

A static block runs once, when the class loads. It runs before any object exists, and it never runs again.

public class Config {

    static String environment;

    static {
        environment = System.getProperty("env", "production");
        System.out.println("Static block ran, env = " + environment);
    }
}

Use it to prepare static fields that need real logic. Loading a driver or reading a config file are classic examples.

6.2 The Instance Block

An instance block runs every single time you create an object. It fires just before the constructor body.

public class Student {

    String name;

    {   // instance initializer block
        name = "Unknown";
        System.out.println("Instance block ran");
    }

    public Student() {
        System.out.println("Constructor ran");
    }
}

Honestly, you will rarely need this one. A constructor usually does the job more clearly.

6.3 The Order Everything Runs In

Exam questions love this, and so do interviewers. Java follows a strict order:

  • Static fields and static blocks run first, once, when the class loads
  • Next, on each new, instance fields and instance blocks run
  • Finally, the constructor body runs
public class Demo {

    static { System.out.println("1. static block"); }

    { System.out.println("2. instance block"); }

    public Demo() { System.out.println("3. constructor"); }

    public static void main(String[] args) {
        new Demo();
        new Demo();
    }
}

Output:
1. static block
2. instance block
3. constructor
2. instance block
3. constructor

Read that output carefully. The static block appears once, while the other two repeat for every object.

7. Data Members vs Local Variables

People lump these together, and that causes real confusion. Java treats them very differently.

Aspect Data member (field) Local variable
Declared In the class body Inside a method or block
Default value Yes (0, false, null) None, you must assign it
Lives in Heap or method area The stack
Lifetime As long as the object or class Until the method returns
Access modifiers Allowed Not allowed

One rule captures most of it. Fields always get a default value, and local variables never do.

8. Access Modifiers on Data Members

8.1 The Four Levels

Every data member can carry an access modifier. That modifier decides who is allowed to see it.

  • private keeps the field inside its own class
  • Default, meaning no keyword at all, opens it to the same package
  • protected adds subclasses, even in other packages
  • public throws it open to the entire program

8.2 Why private Wins

Make your fields private and expose them through getters and setters. This is encapsulation, and it pays off fast.

public class Student {

    private int marks;   // nobody outside can touch this directly

    public void setMarks(int marks) {
        if (marks < 0 || marks > 100) {
            throw new IllegalArgumentException("Marks must be 0 to 100");
        }
        this.marks = marks;   // validation happens before assignment
    }

    public int getMarks() {
        return marks;
    }
}

Leave marks public and anyone can set it to -500. The setter gives you a place to say no.

8.3 The this Keyword in Setters

Look closely at that setter. The parameter and the field share a name, which creates an ambiguity.

Java always picks the narrower scope, so the plain name marks refers to the parameter. Writing marks = marks would just assign the parameter to itself.

The keyword this breaks the tie. It means “the current object”, so this.marks reaches the data member.

public void setMarks(int marks) {
    this.marks = marks;   // field  =  parameter
    // marks = marks;     // useless, assigns the parameter to itself
}

Forget the this and your field silently stays at 0. The code compiles happily, which makes the bug harder to spot.

9. When to Use static

9.1 Good Reasons

Reach for static when the value genuinely belongs to the class rather than to any one object:

  • Constants, like static final double PI = 3.14159
  • Counters that track how many objects exist
  • Configuration shared by every instance, such as a database URL
  • Values that would be identical in every object anyway

9.2 Bad Reasons

Plenty of people add static for the wrong reasons. Watch out for these:

  • Silencing the “non-static variable cannot be referenced” error, instead of creating an object
  • Making a field easier to reach from main
  • Storing per-object data like a name or an id
  • Holding mutable state that several threads will touch

Ask yourself one honest question before typing static. Should every object in this program really share this value?

10. Common Mistakes and Pitfalls

10.1 Making a Field static by Accident

This is the classic. A student id turns static, and suddenly every student has the same id.

The compiler stays quiet, because nothing is technically wrong. Your data quietly turns to nonsense at runtime instead.

public class Student {
    static int studentId;   // bug: should be an instance member
}

Student a = new Student();
Student b = new Student();
a.studentId = 101;

System.out.println(b.studentId); // Output: 101, but b was never assigned

Remove the keyword and the problem disappears. Each student gets a private id again, exactly as you intended.

10.2 Reaching for a Field From main

You hit the “non-static variable cannot be referenced from a static context” error, so you slap static on the field.

Resist that urge. The error is telling you something true, namely that no object exists yet. Create one.

10.3 Sharing Mutable static State Across Threads

Every object shares a static field, which also means every thread shares it.

Picture two threads running count++ at the same time. Both read 5, both write 6, and one increment simply vanishes.

The operation looks atomic in your source code, but it is not. Under the hood it reads, adds, then writes, and a thread can be interrupted midway.

Keep static fields final where you can. When they must change, guard them with synchronisation or use AtomicInteger.

10.4 Leaving Fields public

Public fields let any class reach in and change your object however it likes. Validation becomes impossible.

Worse, you can never add a rule later without breaking every caller. The moment a field goes public, it becomes part of your contract.

Default to private. Open things up later, only when you have a reason.

11. final Data Members

You can mark any data member final. That gives it exactly one assignment, and then it locks forever.

11.1 static final: The True Constant

Pair the two keywords and you get a real constant. One shared copy, and nobody can ever change it.

public class Circle {

    static final double PI = 3.14159;   // one copy, locked forever

    double radius;

    double area() {
        return PI * radius * radius;
    }
}

Notice the naming. Constants use UPPER_SNAKE_CASE, so any reader spots them instantly.

Almost every constant you meet in Java looks like this. Integer.MAX_VALUE and Math.PI both follow the same pattern.

11.2 final Without static

Drop the static and the meaning shifts. Each object still gets its own copy, but each copy locks after one assignment.

public class Student {

    private final int rollNumber;   // one per object, set once

    public Student(int rollNumber) {
        this.rollNumber = rollNumber;   // the only chance to assign it
    }
}

Every student gets a different roll number, yet no student can ever change theirs. That combination is genuinely useful.

Java lets you assign a final instance field in the constructor. After that, the door closes.

12. A Practical Walkthrough

Let us pull the whole article into one small class. A bank account uses both kinds of data member.

12.1 Building the Account Class

The bank name and the interest rate are the same for every account. The balance and the holder are not.

public class Account {

    static final String BANK = "Java Bank";  // constant, shared
    static int accountCount = 0;             // shared counter

    private final String holder;   // one per object, locked after construction
    private double balance;        // one per object, changes often

    public Account(String holder, double opening) {
        this.holder = holder;
        this.balance = opening;
        accountCount++;            // every new account bumps the shared count
    }

    void deposit(double amount) {
        double updated = balance + amount;   // local variable
        balance = updated;
    }

    public static void main(String[] args) {

        Account a = new Account("Rohit", 1000);
        Account b = new Account("Virat", 5000);

        a.deposit(500);

        System.out.println(a.balance);        // Output: 1500.0
        System.out.println(b.balance);        // Output: 5000.0
        System.out.println(Account.accountCount); // Output: 2
        System.out.println(Account.BANK);      // Output: Java Bank
    }
}

12.2 Reading the Class Back

Walk through it once more. Every idea from this article turns up somewhere:

  • BANK is static and final, so one shared copy that nobody can reassign
  • accountCount is static, so both accounts increment the very same counter
  • holder is final but not static, giving each account its own locked name
  • balance is a plain instance field, different per account and free to change
  • updated is local, so it dies the moment deposit returns

Look at the two balances. They moved independently, exactly as instance members should.

Now look at the count. It reached 2, because static members refuse to be duplicated.

13. Interview Questions

Q: What is the difference between instance and static data members in Java?

A: An instance data member gets a fresh copy in every object, and its memory arrives when you call new. A static data member has just one copy for the whole class, created when the class loads. Every object shares that single copy.

Q: Can we access instance variables directly inside the main method?

A: No. The main method is static, so it runs before any object exists. Java would not know which object’s field you meant. Create an object first, then reach the field through it.

Q: When is memory allocated for static variables?

A: The JVM allocates it once, when the classloader first loads the class into memory. It does not wait for an object. That is exactly why you can use a static field without ever calling new.

Q: What happens if two objects modify the same static variable?

A: Both objects read and write the exact same memory, because only one copy exists. A change made through one object becomes visible through every other object immediately, and through the class name too.

Q: Do data members get default values?

A: Yes. Both instance and static members start at 0, 0.0, false, or null depending on their type. Local variables are the exception. They get nothing, so you must assign a value before reading one.

Q: In what order do static blocks, instance blocks, and constructors run?

A: Static blocks run first, once, when the class loads. After that, every call to new runs the instance block, then the constructor body. So a static block appears once in the output, while the other two repeat per object.

Q: Can static data members be accessed without creating an object?

A: Yes, and that is the preferred way. Use the class name, such as Student.count. Reaching a static field through an object still compiles, but it wrongly suggests the value belongs to that object.

Q: Where are instance and static variables stored in memory?

A: Instance variables live on the heap, inside the object that owns them. Static variables live in the method area, which belongs to the class itself. Local variables live on the stack and vanish when the method returns.

Q: Why is a static counter used to count objects?

A: Because the count belongs to the class, not to any single object. A static counter survives across every new call and keeps one running total. An instance counter would reset to zero inside each new object.

Q: What is the difference between static final and final in Java?

A: A static final member is a true constant. One copy exists for the class, and nobody can reassign it. A plain final member gives each object its own copy, which locks after a single assignment, usually inside the constructor. So every object can hold a different value, yet none of them can change it later.

Q: Why do setters use this.name = name?

A: The parameter shares its name with the data member, so the plain name refers to the parameter. Adding this points Java at the current object’s field instead. Leave out the this and you assign the parameter to itself, which compiles fine but leaves the field untouched.

Q: Are static data members thread safe?

A: Not by default. One copy is shared by every object, which also means every thread touches the same memory. Two threads updating the same static counter can lose an update. Keep static fields final, or guard them with synchronisation.

Q: Can a data member and a local variable share the same name?

A: Yes, and Java calls that shadowing. Inside the method, the local name wins, and the data member hides behind it. Reach the field with this.name whenever you need it.

14. Conclusion

Let us wrap up what we covered. Data members are the fields inside a class, and Java offers two kinds.

Instance members give each object its own copy, allocated when you call new. Use them for data that genuinely differs between objects, like a name or a roll number.

Static members hand one shared copy to the entire class, allocated the moment the class loads. Save them for constants, counters, and configuration that everything should share.

Before you type static, pause and ask the question one more time. Should every object really share this value? If the answer is no, leave the keyword out.

Keep your fields private, reach them through getters and setters, and let the compiler protect you. Those habits pay off long before your first big project.

Further Reading

Leave a Comment