What are the issues with protected class-member access? - java

Java has a protected mode for the members of its classes that allow sub-classes access to them. I read somewhere that there are issues with this. The only issue I can think of is that a programmer might forget the protected members are part of the API and cannot be change arbitrarily. Are there other issues?

Of the four member access levels, private and default (package-private) are concordant with encapsulation, i.e. members that are hidden preserve the autonomy of your implementation details. In other words, the less that the users of your API know about your class implementation details, the less you are tied to that implementation and the freer you are to change it at any time without breaking the contracts your API users have relied upon.
As soon as you go up to protected access (and public access) then you are bound to that implementation and must continue to support it until your API's life ends (or you go out of business). Accessible members tend to tie you to a particular implementation, even if you'd like to change it, so ... lots of accessible members are not concordant with tight encapsulation.
But more than that, access also exports risk. The more aspects of your class that are exported by your API, then there are more potential exploits that malicious users can try and hack.
Protected access, for example, can be used to override methods in your class that you had forgotten to make final. This can break your API and, worse, enable malicious users to access instance data that you did not intend to allow.

First, I'm not seeing that a protected member of any class could be considered part of a public API, given that a protected field or function is not visible to the world.
Ultimately, when writing an API, the idea is to have the interface, or contract, be as unchanging as possible; how it's done can change with each revision (although hopefully, not too much).
One issue I could potentially see with protected members in classes would be overriding their behavior to produce radically divergent behavior from the parent, while satisfying the generic contract of the API (that is, if I'm expecting a numerical value, I get it back; if I'm expecting a boolean, I get it back. The correctness of the value/boolean is suspect, though, and should be tested).
Example: Suppose I have a class Parent and a class Child. Both implement an interface called Teachable. This allows them to learn a particular Subject, which is a simple enumeration construct. The contract for Teachable is given as:
public interface Teachable {
/**
* Learn a particular subject.
* This requires that the element being learned hasn't previously been learned.
* #param thisSubject the subject to be learned
* #return whether or not the subject learned was unique.
*/
public boolean hasLearned(Subject thisSubject);
}
Suppose now we have our implementation of the Parent and Child classes as follows:
public class Parent implements Teachable {
private Set<Subject> subjectsLearned = new HashSet<>();
#Override
public boolean hasLearned(final Subject thisSubject) {
return learn(thisSubject);
}
protected boolean learn(final Subject theSubject) {
return subjectsLearned.add(theSubject);
}
}
class Child extends Parent {
private Set<Subject> subjectsLearned = new HashSet<>();
#Override
public boolean hasLearned(final Subject thisSubject) {
return learn(thisSubject);
}
#Override
protected boolean learn(final Subject theSubject) {
return !subjectsLearned.add(theSubject);
}
}
I've effectively changed the behavior of the class which is said to adhere to the behavior of my API, because I could override it. The first time a Child learns a particular Subject, they'll claim they already know it. Only the second and subsequent times would they not.

Related

If we can access private data members using Accessors than why cant we access private methods?

We can access Private data members using accessor method such as
private int num=5;
public int get_num()
{
return num;
}
and we can access the returned value from any class even though num is private data member.
So on Similar note cant we create accessor method that returns private methods?
I just had a thought about it,If we cannot do this please explain.Thank You
Private methods are created when refactoring your code. They are implementation details, which nobody outside needs to know. They are used inside public methods, which are supposed to provide the functionality you want to provide to your client(each public method can be called an API which is used/consumed by other classes i.e. its clients).
Access modifiers are provided to help you achieve proper abstraction. So anything marked private is directly accessible only inside your class. But if you want someone outside to read/write its value, you expose it via getters/setters. Similarly private methods are not accessible outside the class. But nobody is stopping you from creating public method that only calls this private method. This way you do achieve access to private method. But it would be a very poor design.
You can access private method via public method. This is sometimes used to wrap complicated private method and expose simpler, public API.
class Delegator {
private void doPrivateStuff(int param) { ... }
public void doStuffOnce() {
doPrivateStuff(1);
}
public void doStuffIfConditionIsMet() {
if(condition) {
doPrivateStuff(1);
}
}
}
You can also access private methods using reflection.
http://tutorials.jenkov.com/java-reflection/private-fields-and-methods.html
Because the accessor is public, it can be accessed from outside the class; even if it returns private data.
The access modifier of the returned data isn't relevant, only the access modifier of the method matters.
If you created a public method that returned a reference to a private method, yes, you could then call the private method from outside the class. That would entirely defeat the purpose of making the method private however.
You my be wondering "why make a public getter to a private variable". The answer is that although it's possible to retrieve the private data, it isn't possible (unless you create a public setter as well) to change the public data. This assumes that the private days is immutable. If it's mutable, retuning a reference to private data negates any protection you get from making the variable private.
TL;DR
Accessing private methods violates the basic object oriented principle of encapsulation. The question is not "can we access a private method?" but "should we ever do it?". It contradicts the principle of information hiding and it breaks the contract an object "offers" to its consumers. Objects or classes that enforce you to do that should be considered poorly designed.
Why you shouldn't access private members
First a classes should implement a part of your domain logic that is so closely related that there are little interactions necessary with the outside world to fulfill its duties (this is called high cohesion). You then define a public interface for your class / object with functionality that you expose to the outside world - consumers of your object must only use this interface (this is called loose coupling).
Private methods can be seen as a way to structure your code inside your class in a better readable way - they are not intended to be shared with the outside world. Consider them as a "safe space" for the developer of the class to make arbitrary changes without breaking the contract. That's the reason why there can be bad side effects if you actually access private methods: your code is likely to break it the developer of the class decides to change the implementation of such a method. Effective Java, Chapter 4, Item 13 explains this for protected members:
For members of public classes, a huge increase in accessibility occurs when the access level goes from package-private to protected. A protected member is part of the class's exported API and must be supported forever. Also, a protected member of an exported class represents a public commitment to an implementation detail.
Exceptions
The only exception I know from the rule of "not accessing private members outside of an object" is in testing, when you either want to reset a certain variable (e.g. a Singleton) or you want to facilitate the testing of complex logic by testing the private parts of the implementation and hence reducing complexity in testing.

Why does Java 8 not allow non-public default methods?

Let's take an example:
public interface Testerface {
default public String example() {
return "Hello";
}
}
public class Tester implements Testerface {
#Override
public String example() {
return Testerface.super.example() + " world!";
}
}
public class Internet {
public static void main(String[] args) {
System.out.println(new Tester().example());
}
}
Simply enough, this would print Hello world!. But say I was doing something else with the return value of Testerface#example, for instance initializing a data file and returning a sensitive internal value that shouldn't leave the implementing class. Why does Java not allow access modifiers on default interface methods? Why can't they be protected/private and potentially elevated by a subclass (similar in how a class that extends a parent class can use a more visible modifier for an overridden method)?
A common solution is moving to an abstract class however in my specific case, I have an interface for enums, so that does not apply here. I imagine it was either overlooked or because the original idea behind interfaces that they are a "contract" of available methods, but I suppose I want input as to what's going on with this.
I've read "Why is “final” not allowed in Java 8 interface methods?", which states:
The basic idea of a default method is: it is an interface method with a default implementation, and a derived class can provide a more specific implementation
And it sounds to me like visibility wouldn't break that aspect at all.
As with the linked question since it looks like it had trouble being closed, an authoritative answer would be appreciated in this matter, rather than opinion-based ones.
As we saw in What is the reason why “synchronized” is not allowed in Java 8 interface methods? and Why is "final" not allowed in Java 8 interface methods?, extending interfaces to define behavior is more subtle than it might first appear. It turns out that each of the possible modifiers has their own story; its not simply a matter of blindly copying from how classes work. (This is at least obvious in hindsight, as tools for OO modeling that work for single inheritance do not automatically work for multiple inheritance.)
Let's start with the obvious answer: interfaces have always been restricted to only having public members, and while we added default methods and static methods to interfaces in Java 8, that doesn't mean we have to change everything just to be "more like" classes.
Unlike with synchronized and final, which would have been serious mistakes to support for default methods, weaker accessibilities, especially private, are reasonable features to consider. Private interface methods, whether static or instance (note that these would not be defaults, since they do not participate in inheritance) are a perfectly sensible tool (though they can be easily simulated by nonpublic helper classes.)
We actually did consider doing private interface methods in Java 8; this was mostly something that just fell off the bottom of the list due to resource and time constraints. It is quite possible this feature might reappear on the to-do list some day. (UPDATE: private methods in interfaces were added in Java 9.)
Package and protected methods, however, are more complicated than they look; the complexity of multiple inheritance and the complexity of the true meaning of protected would interact in all sorts of no-so-fun ways. So I wouldn't hold your breath for that.
So, the short answer is, private interface methods is something we could have done in 8, but we couldn't do everything that could have been done and still ship, so it was cut, but could come back.

Abstraction in OOPs

I have come across few definitions over the years, and have never able to clearly understand what abstraction is.
I have understood the 3 main concepts of Oops but have had difficulties with this particular concept which is engraved within these other concepts.
Till now i have come to 2 conclusions, but not sure.
It is the ability to hide the implementation details of a method(Behavior), and provide the user with just the interface.
It is ability to define a method signatures(ie. only to declare them) without actually implementing them.
Which is the correct definition of abstraction with context to Object oriented programming, and if not one of the above, then what is it?
Would appreciate if supporting code is also provided :)
It is the ability to hide the implementation details of a method(Behavior), and provide the user with just the interface.
Sort of, but that's "encapsulation". They're related in the sense that "encapsulation" is a key concept of object oriented design whereas "abstraction" is a potential result of that concept.
It is ability to define a method signatures(ie. only to declare them) without actually implementing them.
That's an implementation detail, not the conceptual notion of abstraction itself.
In a simple inheritance model, "abstraction" can be thought of as referring to an object by one of its ancestor (or more abstract) types. For example, consider a hierarchy:
Lifeform
Animal
Canine
Golden Retriever
If you're performing an operation specific only to a Golden Retriever, then you can't perform that operation on any Animal. It has to be a specific Animal. So you need that specific implementation.
However, if you're performing an operation that's generic to all Lifeforms then it doesn't matter what specific implementation you receive. That operation is abstracted so that it can accept any Lifeform object, regardless of the more specific implementation.
Interfaces provide another implementation mechanism which can achieve abstractions. Object composition is still another mechanism. For example, consider this non-inheritance scenario:
public class MyObject {
private ThirdPartyObject dependency;
public MyObject() {
// initialize the dependency
}
public boolean getValue() {
return this.dependency.getValue();
}
public void setValue(boolean value) {
this.dependency.setValue(value);
}
}
This doesn't use inheritance or interfaces for anything, but it does create an abstraction. Consuming code doesn't know anything about the ThirdPartyObject or the details of its implementation. Following the Law Of Demeter the details of that implementation have been abstracted behind a custom object which you control. This can be very useful for de-coupling your code from implementation details you don't control.
Abstraction is a process where you show only “relevant” data and “hide” unnecessary details of an object from the user.
For example, when you login to your Amazon account online, you enter
your user_id and password and press login, what happens when you press
login, how the input data sent to amazon server, how it gets verified
is all abstracted away from the you.
Another example of abstraction: A car in itself is a well-defined
object, which is composed of several other smaller objects like a
gearing system, steering mechanism, engine, which are again have their
own subsystems. But for humans car is a one single object, which can be managed by the help of its subsystems, even if their inner details
are unknown.
Also to be noted that abstraction hides the implementation details but implementation can be shown even i.e. member functions with definitions can also be present, unlike Interface which provides total Abstraction.
Source: BeginnersBook.com
My summary is "hiding the details"; in the case of programming, abstraction is more like your first definition.
For supporting code, you don't really need to look too far. Abstraction is all around. Consider the common data structure string.
A string within a computer is actually bytes converted to a specific character set strung together. (no pun intended)
Therefore, when you put "hello, world" to you, it's a phrase in quotes. When the computer run it, it creates a data structure string which itself contains the bytes and various state to represent the given string. You don't (usually) care how the string object is working. It does and you move on with your goal. That is as basic of an example of abstraction as I can get.
Abstraction is the process by which data and programs are defined with a representation similar in form to its meaning, while hiding away the implementation details.Abstraction involves the facility to define objects that represent abstract “actors” that can perform work, report on and change their state, and “communicate” with other objects in the system.
Abstraction can be seen in two ways:
Data Abstraction - Data abstraction is the way to create complex data types and exposing only meaningful operations to interact with data type, where as hiding all the implementation details from outside works.
Control Abstraction - Abstraction of behavior. Provides an easier, higher level API to hide client from unnecessary execution details.
Abstraction is a way to promise that a class implementing a given abstraction will have a given behaviour. Thus, abstract classes cannot be directly instantiated, they first need to implement the abstraction.
Abstract classes are thus meant to be implemented by a concrete class that declares and defines a method matching the abstract contract. An abstraction can however provide some concrete behaviours along with abstract ones.
Abstraction is done in Java through abstract classes and through interface. In C++, abstraction is achieved through the usage of virtual methods inside a class. Note that Java interfaces were only created as (unlike C++) multiple inheritance is not allowed in this language.
In simple terms
Abstraction: Showing what is necessary and hiding unnecessary details. Ex if your class has 10 functions but only 2 should be useful by the consumer of the class that you make those functions as public and other are private, so what is visible to the consumer is what is needed, instead of showing it all.
Encapsulation: Hiding the complexity to the consumer of the class. Ex. if your class needs two variables to store min and max, you encapsulate them under getter and setter and implement all the validations and checks in the getter and setter. this way you hide the complexities.
Well I will explain abstraction with a real world example. Say in your house you do have an electric plug and many devices can connect to the same plug but plug will never have an idea which device it is connected to, in other words the details of the devices is abstracted (hidden) to the plug.
Think what if we connect a device directly to electric wire without a plug? Say connect a bulb directly to a wire, then wire knows which device it is connected to and when ever we need to replace the bulb then we have to remove the wire connection from the bulb, which means bulb is tightly coupled with the wire. In other words bulb and wire knows the details where it is connected to, means not abstracted.
In object oriented world abstraction works exactly same. The class which consume other classes function/property doesn't need to know which classes function/property it is consuming and everything should be abstracted with an interface / abstract class.
Let me code the same example. Here I have a class "ElectricPlug", which is running a device. But the class "ElectricPlug" doesn't have any idea which device it is running. It can be any class implementing the interface "IDevice", which means the implementation of "RunDevice" is abstracted from "ElectricPlug". Here is the full sample code,
class Program
{
static void Main(string[] args)
{
ElectricPlug electricPlug = new ElectricPlug(new Bulb());
}
}
public class ElectricPlug
{
private readonly IDevice _device;
public ElectricPlug(IDevice device)
{
_device = device;
}
public void Run()
{
_device.Rundevice();
}
}
public interface IDevice
{
void Rundevice();
}
public class Bulb : IDevice
{
public void Rundevice()
{
Console.WriteLine("Switched on bulb");
}
}
public class ElectricPlug
{
private readonly IDevice _device;
public ElectricPlug(IDevice device)
{
_device = device;
}
public void Run()
{
_device.Rundevice();
}
}
There are two parts of object in oops
state ( properties )
behavior ( methods )
so to hiding the implementation of behavior of any object is known as abstraction
let's take a example -->
there is a cook at my home which makes delicious food . some body comes at my home and take dinner . after dinner they asked me that who made this food . i answered
i have a cook whose name is tttt , his address is tttt and his number is 0000 ( these all are the properties of cook object )
they again asked how he made this then i answered
i don't know how he made . i only know that he can make food
so abstraction means we are telling that what task our object can do instead of how my object can do a task .

Java method keyword "final" and its use

When I create complex type hierarchies (several levels, several types per level), I like to use the final keyword on methods implementing some interface declaration. An example:
interface Garble {
int zork();
}
interface Gnarf extends Garble {
/**
* This is the same as calling {#link #zblah(0)}
*/
int zblah();
int zblah(int defaultZblah);
}
And then
abstract class AbstractGarble implements Garble {
#Override
public final int zork() { ... }
}
abstract class AbstractGnarf extends AbstractGarble implements Gnarf {
// Here I absolutely want to fix the default behaviour of zblah
// No Gnarf shouldn't be allowed to set 1 as the default, for instance
#Override
public final int zblah() {
return zblah(0);
}
// This method is not implemented here, but in a subclass
#Override
public abstract int zblah(int defaultZblah);
}
I do this for several reasons:
It helps me develop the type hierarchy. When I add a class to the hierarchy, it is very clear, what methods I have to implement, and what methods I may not override (in case I forgot the details about the hierarchy)
I think overriding concrete stuff is bad according to design principles and patterns, such as the template method pattern. I don't want other developers or my users do it.
So the final keyword works perfectly for me. My question is:
Why is it used so rarely in the wild? Can you show me some examples / reasons where final (in a similar case to mine) would be very bad?
Why is it used so rarely in the wild?
Because you should write one more word to make variable/method final
Can you show me some examples / reasons where final (in a similar case to mine) would be very bad?
Usually I see such examples in 3d part libraries. In some cases I want to extend some class and change some behavior. Especially it is dangerous in non open-source libraries without interface/implementation separation.
I always use final when I write an abstract class and want to make it clear which methods are fixed. I think this is the most important function of this keyword.
But when you're not expecting a class to be extended anyway, why the fuss? Of course if you're writing a library for someone else, you try to safeguard it as much as you can but when you're writing "end user code", there is a point where trying to make your code foolproof will only serve to annoy the maintenance developers who will try to figure out how to work around the maze you had built.
The same goes to making classes final. Although some classes should by their very nature be final, all too often a short-sighted developer will simply mark all the leaf classes in the inheirance tree as final.
After all, coding serves two distinct purposes: to give instructions to the computer and to pass information to other developers reading the code. The second one is ignored most of the time, even though it's almost as important as making your code work. Putting in unnecessary final keywords is a good example of this: it doesn't change the way the code behaves, so its sole purpose should be communication. But what do you communicate? If you mark a method as final, a maintainer will assume you'd had a good readon to do so. If it turns out that you hadn't, all you achieved was to confuse others.
My approach is (and I may be utterly wrong here obviously): don't write anything down unless it changes the way your code works or conveys useful information.
Why is it used so rarely in the wild?
That doesn't match my experience. I see it used very frequently in all kinds of libraries. Just one (random) example: Look at the abstract classes in:
http://code.google.com/p/guava-libraries/
, e.g. com.google.common.collect.AbstractIterator. peek(), hasNext(), next() and endOfData() are final, leaving just computeNext() to the implementor. This is a very common example IMO.
The main reason against using final is to allow implementors to change an algorithm - you mentioned the "template method" pattern: It can still make sense to modify a template method, or to enhance it with some pre-/post actions (without spamming the entire class with dozens of pre-/post-hooks).
The main reason pro using final is to avoid accidental implementation mistakes, or when the method relies on internals of the class which aren't specified (and thus may change in the future).
I think it is not commonly used for two reasons:
People don't know it exists
People are not in the habit of thinking about it when they build a method.
I typically fall into the second reason. I do override concrete methods on a somewhat common basis. In some cases this is bad, but there are many times it doesn't conflict with design principles and in fact might be the best solution. Therefore when I am implementing an interface, I typically don't think deeply enough at each method to decide if a final keyword would be useful. Especially since I work on a lot of business applications that change frequently.
Why is it used so rarely in the wild?
Because it should not be necessary. It also does not fully close down the implementation, so in effect it might give you a false sense of security.
It should not be necessary due to the Liskov substitution principle. The method has a contract and in a correctly designed inheritance diagram that contract is fullfilled (otherwise it's a bug). Example:
interface Animal {
void bark();
}
abstract class AbstractAnimal implements Animal{
final void bark() {
playSound("whoof.wav"); // you were thinking about a dog, weren't you?
}
}
class Dog extends AbstractAnimal {
// ok
}
class Cat extends AbstractAnimal() {
// oops - no barking allowed!
}
By not allowing a subclass to do the right thing (for it) you might introduce a bug. Or you might require another developer to put an inheritance tree of your Garble interface right beside yours because your final method does not allow it to do what it should do.
The false sense of security is typical of a non-static final method. A static method should not use state from the instance (it cannot). A non-static method probably does. Your final (non-static) method probably does too, but it does not own the instance variables - they can be different than expected. So you add a burden on the developer of the class inheriting form AbstractGarble - to ensure instance fields are in a state expected by your implementation at any point in time. Without giving the developer a way to prepare the state before calling your method as in:
int zblah() {
prepareState();
return super.zblah();
}
In my opinion you should not close an implementation in such a fashion unless you have a very good reason. If you document your method contract and provide a junit test you should be able to trust other developers. Using the Junit test they can actually verify the Liskov substitution principle.
As a side note, I do occasionally close a method. Especially if it's on the boundary part of a framework. My method does some bookkeeping and then continues to an abstract method to be implemented by someone else:
final boolean login() {
bookkeeping();
return doLogin();
}
abstract boolean doLogin();
That way no-one forgets to do the bookkeeping but they can provide a custom login. Whether you like such a setup is of course up to you :)

protected data in abstract class

My question involves specifically Java, abstract classes, and the use of protected data. I am being told that all the data should be private, and protected getters/setters used only.
Now, I understand we want to shield data from direct manipulation by casual users of the class, and that public data members in general are a questionable practice. I have looked at "Java protected fields vs public getters" ( Java protected fields vs public getters ), but I still am dubious that:
protected int i;
is worse in an abstract class than:
private int i;
protected int geti();
protected void seti(int j);
I am just not seeing the down side when the abstract class is there precisely to provide parent/common facility to the children classes, and the protected scope is meant to provide access to children, while protecting the data from casual users. I note in the question referenced above, that most of the answers seem to address the issue of why data in general should be private rather than public. I am trying to focus my question specifically on data existing in an abstract parent intended for use by the children. The sole reasonable comment I have heard to date is that using the parents protected data (e.g., int i above) leaves you with code in the child class that references a variable not declared in the child class. Less compelling is the argument (see Common protected data member in base class? ) that you may want to change the access some day, and now you have to honor your interface. This is an abstract class, and is intended to be extended 100% of the time.
Thanks! Specific Title/page# references to books are far more helpful that references to "..any basic Java programming text..."
========================================== 10-13-2010
This was as much a question about abstract classes as it is about protected data. I find it disappointing that the focus seems to have shifted in the responses to whether data hiding is a good thing in OOP (answer: yes). There's a lot of depth here involving the nature of the abstract class, and how it differs from a regular non-final class, and what possible advantages there might be for fixing the names and types of data-items in the abstract parent for use by the child classes. I think there is the possibility here for innovation and greater control being extended down from the abstract parent to the implementing child classes. I am concerned that general principles, such as the advantages of data-hiding, can become dogma, and inhibit innovation and the development of new patterns and ideas.
Thanks to all who contributed.
If the field is private and access is through getters and setters, you will be able to reimplement getters and setters (for instance, dropping the field and updating/reading the value from an external source), and thus change how the "field" works without touching any child classes.
Whether this is worth it, that's up to you.
Think of protected methods as an interface for subclasses, in the same way that public methods are an interface for everyone else.
Providing accessors enables the base class to maintain its state: there's no way a subclass would corrupt it without an intentional trick.
Having less access isn't a drawback, it's a benefit. Classes should always limit access to as much of their internal state as possible. Don't think of why internals should be hidden, instead think of why they should be exposed. In this case as in every case, unless there is a really good reason to expose the variable then don't expose it.
In Java protected members are accessible to all members in the same package in addition to any extending classes. Making the field private will prevent classes in the same package from directly accessing it.
As well there is the point that alex raised earlier.
If you don't need your child to directly access it, why would you let them ?
It isn't a down side to use protected. But if it isn't necessary, maybe it's better to avoid it and control access on your fields.
If someone subclasses your class, and puts the subclass in the same package as your current class, they may want to override your getters and setters. For example, they wantto make sure that i may only be set to a value greater than 1.
Other than that, it's really up to you. The convention is that there are getters and setters for everything though.
Information hiding is valuable, even among classes related by inheritance.
In addition to allowing re-implementation, as noted by alex above:
You can set breakpoints in methods.
You can add constraints in one place.
You want to use getters/setters because using protected int i; allows for field overriding (which you want to avoid at all costs).
You want to disallow field overriding because it works differently than method overriding. Field overriding does not make the overridden field inaccessible (the type of the reference determines which instance of the field you are working with).
Accessible fields should be final or in a class that is final.
public class OverridingFun {
public static class Base {
public int i = 1;
public int getI(){ return i; }
}
public static class A extends Base {
public int i = 2;
public int getI(){ return i; }
}
public static class B extends A {
public int i = 3;
public int getI(){ return i; }
}
public static void main(String [] args){
B b = new B();
A bAsA = b;
Base bAsBase = b;
System.out.println(b.getI());//3
System.out.println(bAsA.getI());//3
System.out.println(bAsBase.getI());//3
System.out.println(b.i);//3
System.out.println(bAsA.i);//2
System.out.println(bAsBase.i);//1
b.i = 4;
bAsA.i = 5;
bAsBase.i = 6;
System.out.println(b.i);//4
System.out.println(bAsA.i);//5
System.out.println(bAsBase.i);//6
}
}
At first glance this looks like something that would just make code hard to read but it has implications on functionality. Say the field does get overridden by a derived class, since setters are not being used, there is no way to automagically update the base field and no way to detect if someone has changed the base field (since the base value is still accessible) and update the derived field. It's easy to imagine that the base and derived states could get out of sync and that the errors would be hard to track down. Simply put it makes for a very brittle API.
Unfortunately there is no way to guard against this since the final keyword, which protects against overriding, also makes fields write-once. So no writable non-overloadable fields.
Personally I'm rather surprised the language designers allowed field overriding at all. The advantage of using setters is that each level can guaranty the integrity of it's own state and trust that derived classes haven't fouled it up. Field overriding is just asking for trouble.

Categories