'Can a class have an abstract class as attribute in Java?

I have an abstract class Product

public abstract class Product implements Serializable {
   private Integer id;
   private LocalDateTime creationDate;
   private LocalDateTime updateDate;
   //constructors etc..
}

then I have multiple child classes that extend Product and an Ad class which lists the products. My question is: can I use the Product class as an attribute? so it could be instantiated with the different child classes like this:

public class Ad implements Serializable {
   private Integer id;
   private Product product;
   //constructors and methods..
}


Ad example = new Ad(1,childClass);


Solution 1:[1]

Your question is whether you can use the Product class which is the abstract class as an attribute so it could be initiated with the different child class implementation of it ? Answer is yes!

I will add a simple example below:

Abstract class

public abstract class AbstractClass {

  abstract void test();

}

Child class

public class ChildClass extends AbstractClass {

  @Override
  void test() {

  }

}

Example usage

public class Example {

  private static AbstractClass abstractClass;

  public static void main(String[] args) {
    abstractClass = new ChildClass();
  }

}

Hope this answers your question.

Solution 2:[2]

Yes, member field can be an abstract type

?? Yes, a member field may be of a type that is abstract.

Of course you will need to use a concrete implementation of that abstract class to instantiate an object to populate that field.

Alternate example

Here is a different example, to be a bit more concrete (pardon the pun). We have an unrealistic portrayal of a veterinary clinic with animal patient visits.

In this example, we show an abstract class (Pet) as a member field (on Visit), with either of two concrete classes (Cat, Dog) used to populate that field.

A Visit is a record consisting of a date and a Pet object.

record Visit( LocalDate date , Pet pet ) { }

The Pet class is abstract. This abstract class defines a read-only property of name, for the name of each patient animal.

abstract class Pet { … }

So we have concrete classes Cat & Dog which extend Pet. These concrete classes inherit the name property from their abstract superclass.

class Cat extends Pet { … }
class Dog extends Pet { … }

We declare the Visit member field to be of type Pet while we populate with concrete classes for cats and dogs.

new Visit( LocalDate.of( 2022 , Month.JANUARY , 23 ) , fluffy )   // Cat
…
new Visit( LocalDate.of( 2022 , Month.MARCH , 23 ) , rover )  // Dog

?? Notice how I used this.getClass().getSimpleName() in the toString override on Pet. This shows the magic of polymorphism, and verifies how we have objects of a concrete class being held in a member field of an abstract type.

For the example data, we have Fluffy the cat visiting on January 23, with a follow-up visit a month later on February 28. In another month, we have Rover the dog visiting on March 7.

package work.basil.example.vet;

import java.time.LocalDate;
import java.time.Month;
import java.util.List;

public class App
{
    public static void main ( String[] args )
    {
        App app = new App();
        app.demo();
    }

    private void demo ( )
    {
        Cat fluffy = new Cat( "Fluffy" );
        Dog rover = new Dog( "Rover" );

        List < Visit > visits =
                List.of(
                        new Visit( LocalDate.of( 2022 , Month.JANUARY , 23 ) , fluffy ) ,
                        new Visit( LocalDate.of( 2022 , Month.FEBRUARY , 28 ) , fluffy ) ,
                        new Visit( LocalDate.of( 2022 , Month.MARCH , 7 ) , rover )
                );

        System.out.println( "visits = " + visits );
    }

    abstract class Pet
    {
        private String name;

        String getName ( ) /* Getter */ { return this.name; }

        public Pet ( String name )  /* Constructor */ { this.name = name; }

        @Override
        public String toString ( )
        {
            return "Pet{ " +
                    "class=" + this.getClass().getSimpleName() + " | " +
                    "name=" + name +
                    " }";
        }
    }

    class Cat extends Pet
    {
        public Cat ( String name )  /* Constructor */ { super( name ); }
    }

    class Dog extends Pet
    {
        public Dog ( String name )  /* Constructor */ { super( name ); }
    }

    record Visit( LocalDate date , Pet pet ) { }
}

visits = [Visit[date=2022-01-23, pet=Pet{ class=Cat | name=Fluffy }], Visit[date=2022-02-28, pet=Pet{ class=Cat | name=Fluffy }], Visit[date=2022-03-07, pet=Pet{ class=Dog | name=Rover }]]

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Sankalpa Wijewickrama
Solution 2