☰ Contents Java Details

Visibility Modifiers

Student: I have another confusion here. When I make a record, I can access its fields with dot, and you’ve shown that.
Prof: Absolutely!
Student: But I can’t do that with fields on stuff like Circle:
Student: Why won’t it let me access that?
Prof: Great question! This has to do with visibility modifiers.
Student: Visibility modifiers?
Prof: Yeah. So we haven’t really bothered to write them except one – public. We had to add that when we implemented methods from an interface, remember?
Student: Yeah I remember that. You told me to just write it and not question it.

Prof: So all fields and methods can have one of several visibilities, which affect which other classes can use them directly. The ones we’ve been encountering implicitly are:

  • private – the field or method can be accessed only within the class or within classes declared in the same file, for the kind of programs we write (ones with a void main())
  • No modifier given (called “package private”) – the field or method can be accessed only within the class or other classes in files in the same “package” (roughly a folder)
  • public – any context can access the field or method
Student: But I don’t see any code where radius is made private:
record Circle(int radius, Color color) implements Pict {

Pict.java, lines 142–142

Prof: That’s true. What’s happening is record fields have private access. It’s by default and it can’t be changed.
Student: Really? So how have we been able to… oh because the other classes, or main or whatever, are in the same file. But wait, I can access it if I add parentheses:
Prof: Correct. This is a trick records pull off – it’s helpful to be able to see the private fields’ values. So records also add a public accessor method or getter with exactly the name of the field. So going back to our Point class that corresponds to a record, it would actually look like:
Prof: For a record, making the constructor public makes sense because the job of a record is to construct data. So the defaults all make sense. And records are actually doing quite a bit of typing for us (and saving us tedious reading), because we want these patterns over and over.
Student: And why would you want things to be private? It seems like it just adds errors to your program. Things should just be visible.

Prof: You know, I partially agree with you. But there’s a good argument for keeping fields private, and it’s what most people actually recommend! The idea is that it limits where you have to look to see what happens to a particular field. If you want to ask a question like “does this int field only ever increase” that’s a very complicated question to answer if any code in a big program could change it. But if you have all the uses of the field in one place, you can audit that quickly.

Especially these days with agents adding code all the time, things like private help set up some boundaries so you can still check a guarantee like “my field only increases” even if thousands of lines of code are added outside that class.

Student: Huh, that’s actually pretty cool. So that’s it then, that’s how records and classes correspond? No more lies?

Prof: Um, well, the equals method is a little weird. And I left out something called hashCode that is not relevant for what we’re doing right now. We will have to directly address updating equals when we talk about the Object class, but that’ll be another day. There’s one more detail of record that I want to share now, though.

Record fields are what’s called final, which means you can’t do field update on them.

Student: OK, why not?
Prof: The idea with records is that they create fixed data for representing something that doesn’t change. This is super common in programming, and it’s something Java makes easy. In general, fields on class declarations can have field updates applied to those fields. So one step more honest would be to put final in:
Prof: And that is as far as we will go for now.
Student: So I can read all of Pict now?
Prof: A lot more of it, for sure. There’s more to learn still, but I think that gives a good picture of a lot of what I was hiding or sliding past.

Practice

Raster is a class in Pict.java with private fields pixels, width, and height, and methods width(), height(), and colorAt(x, y). In your program, r is a Raster and c is a Circle. Which of these lines compile? Select all that do.
  1. int w = r.width();
    width() is a method of Raster that it lets you call.
  2. int w = r.width;
    width the field is private, so only code inside Raster can use it.
  3. Color first = r.colorAt(0, 0);
    colorAt is how Raster lets you read one pixel.
  4. Color[][] all = r.pixels;
    pixels is private. Raster never hands out its array.
  5. Color col = c.color();
    A record writes an accessor method for every field.
  6. Color col = c.color;
    A record’s fields are private, even when you didn’t write the word.
A record’s fields are private and final. Which of these can code outside the record do?
  1. Read a field’s value, with its accessor method
    The accessor method is public, so anyone can read the value with it.
  2. Change a field’s value after the record is built
    final means no field update, not even inside the record, once it’s built.
  3. Read a field directly, with . and the field name
    From another file, the field itself is private. The accessor method is the way in.