Java >> Java tutorial >  >> Tag >> java.lang

redundant cast til java.lang.Object advarsel for nødvendig cast

Fejlen om en "ambiguous method invocation" er korrekt siden Java 8.

Allerede før Java 8 kunne du skrive

char c = fail();
Object o = fail();

uden compiler fejl. Når du passerer en betinget som condition? 'a': genericMethod() til en metode som String.valueOf(…) , udledte compileren <Object> for fail() og valgte String.valueOf(Object) på grund af dens begrænsede typeslutning.

Men Java 8 introducerede Poly Expressions:

Typen af ​​et selvstændigt udtryk kan bestemmes helt ud fra indholdet af udtrykket; i modsætning hertil kan typen af ​​et polyudtryk være påvirket af udtrykkets måltype (§5 (Konverteringer og kontekster)).

Både en påkaldelse af en generisk metode og en betinget, der indeholder et polyudtryk (dvs. påkaldelsen af ​​en generisk metode), er polyudtryk.

Så prøver at påkalde String.valueOf(char) er gyldig med det betingede, som vi kan udlede <Character> for fail() . Bemærk, at ingen af ​​metoderne er anvendelige i en streng invokationskontekst, da begge varianter kræver en boksning eller unboxing-operation. I en løs invokationskontekst, begge, String.valueOf(Object) og String.valueOf(char) er gældende, da det er ligegyldigt, om vi udpakker Character efter at have påkaldt fail() eller boks char af den bogstavelige 'a' .

Siden char er ikke en undertype af Object og Object er ikke en undertype af char , ingen af ​​metoderne, String.valueOf(Object) heller ikke String.valueOf(char) , er mere specifik, og derfor genereres en kompileringsfejl.

Det er sværere at bedømme advarslen, da der ikke er nogen formel standard for advarsler. Efter min mening er enhver compiler-advarsel, der hævder, at en kildekodeartefakt var forældet på trods af koden, ikke vil gøre det samme efter at have fjernet den (eller at fjerne den vil endda introducere fejl), er forkert. Interessant nok findes advarslen allerede i Java 7's version af javac , hvor det ikke gør nogen forskel at fjerne rollebesætningen, så måske er det en rest, der skal opdateres.

Løsninger til problemet afhænger af konteksten, og der er ikke nok information om det. Vær opmærksom på, at der kun er behov for én gren, som ikke kan tildeles char , for at gøre metoden String.valueOf(char) uanvendelig. Det vil ske, så snart du indsætter grenen, der evaluerer til String . Du kan også bruge SurroundingClass.<Object>fail() for at komme til den samme type, som kompilatorer før Java 8 udledte.

Eller slip helt den generiske signatur, da den ikke er nødvendig her. Den generiske metode fail() synes at være en work-around at have en kastemetode i en udtrykssammenhæng. En renere løsning ville være en fabriksmetode til udtrykket, f.eks.

class Code {
    public static void main(String[] args) throws SpecificExceptionType {
        System.out.println(
            String.valueOf(switch(0) {
                case 0 -> 'a';
                case 1 -> 'b';
                case 2 -> 'c';
                default -> throw fail();
            })
        );
    }
    private static SpecificExceptionType fail() {
        return new SpecificExceptionType();
    }
    static class SpecificExceptionType extends Exception {
    }
}

Hvis skifteudtryk ikke er mulige, kan du bruge

System.out.println(
    String.valueOf(
        true ? 'a' :
        true ? 'b' :
        true ? 'c' :
        Optional.empty().orElseThrow(Code::fail)
    )
);

Begge har fordelen af ​​at være specifikke med hensyn til den faktiske type af potentielt kastede undtagelser og behøver ikke at ty til ukontrollerede undtagelser eller throws Throwable erklæringer. Den anden kan føles hacky, men ikke mere end at definere en generisk metode, der aldrig returnerer noget.

Selvfølgelig er der andre muligheder for at løse det, hvis du bare accepterer introduktionen af ​​mere kode, som en dedikeret hjælpemetode til strengkonvertering uden overbelastning eller en ikke-generisk indpakningsmetode til kastemetoden. Eller en midlertidig variabel eller type casts eller eksplicitte typer for de generiske påkald osv. Yderligere, når du bruger "" + (expression) eller (expression).toString() i stedet for String.valueOf(expression) , udtrykket er ikke et polyudtryk, og det producerer derfor ikke en "ambiguous method invocation"-fejl.

Da dette er en falsk advarsel, kan du selvfølgelig også beholde rollebesætningen og tilføje en @SuppressWarnings("cast") til metoden (og vent indtil dette bliver rettet af kompilatorudviklerne).


Problemet er, at de to grene af den ternære operatør returnerer forskellige typer.

Hvad med dette:

    System.out.println(
        String.valueOf(
            true ? (Object)'a' : fail()
        )
    );

Eksplicit boksning af karakteren er én mulighed:

class Code {
    public static void main(String[] args) throws Throwable {
        System.out.println(
                String.valueOf(
                        true ? Character.valueOf('a') : fail()
                )
        );
    }
    private static <R> R fail() {
        throw null;
    }
}

Java tag