14

Suppose I have four classes in java with given hierarchy.

class A {}
class B extends A {} 
class C extends B {} 
class D extends C {} 

As per my understanding all the accessible fields of class A will be available to all its child classes through inheritance. Now what if I want few fields of class A to be available to class B only.

Is there any way in java so that I can restrict certain fields of parent class to its immediate child class only?

Ronak Thakkar
  • 2,515
  • 6
  • 31
  • 45
user8001621
  • 149
  • 1
  • 5
  • 12
    If this is really what you want, then your class design is most likely wrong. What is the real use case of your question? – small_ticket Nov 23 '17 at 04:47
  • This was asked to me in an interview. They had given me the same scenario. – user8001621 Nov 23 '17 at 04:49
  • 6
    I really don't understand these kinds of questions, which have no real life value, in interviews. It really sucks – small_ticket Nov 23 '17 at 04:59
  • 1
    I don't know about your use case, but be aware of violations of the Liskov substitution principle – Nick Vanderhoven Nov 23 '17 at 07:09
  • 1
    I have a feeling you'd be interested to read [this](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) first. And then on an interview reply with mainly same line even if providing some answer via reflection in this case. – Alma Do Nov 23 '17 at 10:15
  • 1
    @user8001621 Wouldn't recommend taking that job. Sounds like they don't have decent design skills. – jpmc26 Nov 23 '17 at 14:00
  • Initially I also had a same doubt about design flaw. But I wasn't sure so I couldn't take it further in interview. It was my first interview. By the way thank you all. – user8001621 Nov 23 '17 at 16:37

6 Answers6

11

Not that I would do anything like this in production, but here you go:

class A {
    private int a = 1;

    public int getA() {
        if (getClass().equals(A.class) || 
            getClass().getSuperclass().equals(A.class)) {
            return a;
        } else {
            throw new UnsupportedOperationException("hahaha");
        }
    }        

    public static void main(String[] args) {
        A a = new A();
        B b = new B();
        C c = new C();
        System.out.println(a.getA());
        System.out.println(b.getA());
        System.out.println(c.getA());
    }
}

class B extends A {}

class C extends B {}

So basically you can use this trick to allow only classes you want (using either the blacklist or whitelist approach) - to call getA().

OUTPUT:

1
1
Exception in thread "main" java.lang.IllegalStateException: hahaha
    ...
Nir Alfasi
  • 53,191
  • 11
  • 86
  • 129
4

Restricting parent class members to its immediate child class only, For that,

Java provides protected access modifier in which, You can access class members:

1) Within class

2) Within package and

3) Outside the package by Subclass only.

If you want to restrict data members to the immediate child class, then What you can do is:

Declare One class as below:

package com.firstpackage;

Class A{
 protected int a;
}

Now Use the child class in another package like this:

package com.secondpackage;

Class B extends A{
 //Access data members of class A
}

Now if you declare, Class C and D in package com.secondpackage; and extends them from Class B, Then these two classes (Class C and D) are not the direct children of Class Aand of course not in the same package in which Class A is implemented. So the data members of Class A is not accessible in Class C and D.

Ronak Thakkar
  • 2,515
  • 6
  • 31
  • 45
  • 1
    First, you need `public class A{ protected int a; }` because you need to access it from `com.secondpackage`. Then, your member `a` is `protected`, so *every* subclass can access it. So you would need to make it package private: `public class A{ int a;}`. But then `B` can't access `A.a`. Your solution will never work as is. A better solution would be to make `A` and `B` in the same package, *and then* `A.a` package private, *and then* make your package private with Java 9's modularization. – Olivier Grégoire Nov 23 '17 at 14:58
  • 3
    This is simply not true: having classes C and D extend B (which, in return, extends A) in your example will still be able to access a protected field in class A - even if they're in another package! – Nir Alfasi Nov 23 '17 at 14:58
2

This is not right class design but, if you really want to do this, you can manage this scenario.

Like, you want to restrict parent class members to other than immediate child class, you can use protected access modifier and put other class in another package.

As per your example,

Class A and Class B will be in the same package and Class C,D will be another package. You can use protected access modifier for Class A's member.

Samir Bhatt
  • 3,041
  • 2
  • 25
  • 39
0

You can set all your attributes private and access them using getters. Then you can control the visibility and override it.

An example with 3 classes:

    class A{
        private String test = "Test123";
        protected String getTest(){return test;};
    }

    class B extends A{
        @Override
        protected String getTest(){return "no";};
    }

    class C extends B{
    } 

Here the class A shares the test attributes only with B. B can access the A attribute with super.getTest() C cannot access the test.

Its a much cleaner approach than check the class type.

Ananta
  • 660
  • 1
  • 7
  • 19
0

A workaround to achieve the purpose could be refactoring.
Defining an interface or an abstract class Class , implemented/subclassed by A and B, with the variables and the methods in common beetween the two classes.
C and D extend A, inheriting the methods implemetend in A.
The choice beetween the use of interface/abstract class for Class is dictated from the need of reuse common fields and methods in A and B or not.

Jul10
  • 503
  • 7
  • 19
0

By OOPS concept: Designed behavior of class cannot be different for one class and different for another class in inheritance concept.

To stop inheriting the fields to child class make those fields as sealed i.e. private. And if you required fields to be access by only immediate child then mark the fields as protected.

If you need access the fields till last leaf node child class (in this case till Class D) then mark the fields as public.

Or by while designing the class into the components you can restrict the inheritance of one class from another component through OOPS access modifiers at class level.