67

I have the following implementation that gives a compiler error:

public enum FusionStat implements MonsterStatBuilderHelper {
    ATTACK {
        @Override
        public MonsterCard.MonsterCardBuilder safeCreateBuilder(final MonsterCard baseMonsterCard, final MonsterCard fusedMonsterCard, final FusionCard fusionCard) {
            Objects.requireNonNull(baseMonsterCard);
            Objects.requireNonNull(fusedMonsterCard);
            Objects.requireNonNull(fusionCard);
            if (baseMonsterCard.equals(fusedMonsterCard)) {
                throw new IllegalArgumentException("baseMonsterCard and fusedMonsterCard need to be different");
            }
            return new MonsterCard.MonsterCardBuilder(baseMonsterCard)
                    .attack(baseMonsterCard.getAttack() + (fusionCard.getFusionPower() * fusedMonsterCard.getAttack()));
        }
    },

    HITPOINTS {
        @Override
        public MonsterCard.MonsterCardBuilder safeCreateBuilder(final MonsterCard baseMonsterCard, final MonsterCard fusedMonsterCard, final FusionCard fusionCard) {
            Objects.requireNonNull(baseMonsterCard);
            Objects.requireNonNull(fusedMonsterCard);
            Objects.requireNonNull(fusionCard);
            if (baseMonsterCard.equals(fusedMonsterCard)) {
                throw new IllegalArgumentException("baseMonsterCard and fusedMonsterCard need to be different");
            }
            return new MonsterCard.MonsterCardBuilder(baseMonsterCard)
                    .maximumHitpoints((int)(baseMonsterCard.getMaximumHitpoints() + (fusionCard.getFusionPower() / 100d * fusedMonsterCard.getMaximumHitpoints())))
                    .hitpoints((int)(baseMonsterCard.getHitpoints() + (fusionCard.getFusionPower() / 100d * fusedMonsterCard.getHitpoints())));
        }
    };

    protected interface MonsterStatBuilderHelper extends MonsterStatBuilder {
        default MonsterCard.MonsterCardBuilder safeCreateBuilder(final MonsterCard baseMonsterCard, final MonsterCard fusedMonsterCard, final FusionCard fusionCard) {
            return createBuilder(baseMonsterCard, fusedMonsterCard, fusionCard);
        }
    }
}

@FunctionalInterface
interface MonsterStatBuilder {
    MonsterCard.MonsterCardBuilder createBuilder(final MonsterCard baseMonsterCard, final MonsterCard fusedMonsterCard, final FusionCard fusionCard);
}

It gives a cyclic inheritance error on the first line involving FusionStat.

I don't exactly see what is going on. I had first implemented an abstract class and wanted to let the enum extend that, until I realized that enums cannot extend classes. Now I try to (ab)use the default methods in Java 8.

I am interested in the thought process about why my code does not compile, I was trying to remove code duplication (still have to do so), by pulling the duplicated code inside safeCreateBuilder.

skiwi
  • 66,971
  • 31
  • 131
  • 216

3 Answers3

145

This would be because you are implementing (coding) the interface you are implementing (inheriting) inside of the class that is inheriting from that class.

I wish I could make that sentence better...

But here is a visual example.

Class A implements Interface B {

    Interface B {
    }
}

As far as I know, this is not allowed. You need to define the interface outside of the class (in this case, an Enum).

Like so:

Interface B {
}

Class A implements Interface B {
}

Best practice is probably to break them up into different files.

QuestionMarcs
  • 1,672
  • 1
  • 12
  • 15
  • 1
    right! Its always good to define your interfaces in different files (in dedicated package?) – Amol Desai Oct 15 '15 at 06:25
  • 7
    Can't really understand the nature of the problem, but I can confirm that I've also fixed it defining the interface in a different file. Thanks. +1 – voghDev Oct 19 '15 at 05:35
  • That was poetic yet clearly explained in one line. +1. – Talha Nov 11 '16 at 06:43
  • 18
    So this is a completely arbitrary limitation in Java with no technical rationale, right? I understand it as "best practice" to create enormous amounts of boiler plate in this language. – user239558 Jul 24 '17 at 10:03
  • 2
    Interface classes are always static (you cannot add the static qualifier for this reason). That should mean this is not an issue... (but I'm seeing the same in Android Studio today) – Nick Cardoso May 15 '18 at 12:28
  • defining the interface outside of the class really helped thanks. – Unique Identifier Apr 27 '19 at 12:18
1

You can see here what's mistake in your code ?

public enum FusionStat implements MonsterStatBuilderHelper {
   protected interface MonsterStatBuilderHelper extends MonsterStatBuilder {

   }
}

first you are implementing MonsterStatBuilderHelper for FusionStat enum again inside the enum written one more time with the same name interface MonsterStatBuilderHelper which you are already implementing for top level enum so that's why you are getting cyclic inheritance error.

You can see below some few cyclic inheritance example

//1st example 
class Person extends Person {}  //this is not possible in real world, a Person itself child and parent both ?

//2nd example 
class Human extends Person{}
class Person extends Human{}

Notes : cyclic inheritance is not supported in java because logically it's not possible.

-5

FusionStat is defined as implementing MonsterStatBuilderHelper, yet inside this enum you try to declare the interface MonsterStatBuilderHelper which extends MonsterStatBuilder.

I suspect that what you want to do is simply define the method createBuilder() inside your enum.

If you do actually want to define the MonsterStatBuilderHelper interface, this needs to be done outside the class/enum.

Shaishav Jogani
  • 2,111
  • 3
  • 23
  • 33
Danny
  • 354
  • 1
  • 5