In Java gebruiken we final
trefwoord met variabelen om zijn waarden op te geven, mogen niet worden gewijzigd.
Maar ik zie dat u de waarde in de constructor / methoden van de klasse kunt wijzigen. Nogmaals, als de variabele static
is, is het een compilatiefout.
Hier is de code:
import java.util.ArrayList;
import java.util.List;
class Test {
private final List foo;
public Test()
{
foo = new ArrayList();
foo.add("foo"); // Modification-1
}
public static void main(String[] args)
{
Test t = new Test();
t.foo.add("bar"); // Modification-2
System.out.println("print - " + t.foo);
}
}
hierboven-code werkt prima en geen fouten.
Wijzig nu de variabele als static
:
private static final List foo;
Nu is het een compilatiefout. Hoe werkt dit final
echt?
1, Autoriteit 100%
U bent altijd toegestaan om initialiseert A final
variabele. De compiler zorgt ervoor dat u het maar één keer kunt doen.
Houd er rekening mee dat beltemethoden op een object opgeslagen in een final
variabele heeft niets te maken met de semantiek van final
. Met andere woorden: final
is alleen over de referentie zelf, en niet over de inhoud van het object waarnaar wordt verwezen.
Java heeft geen concept van onmetelijkheid van het object; Dit wordt bereikt door het voorwerp zorgvuldig te ontwerpen, en is een ver van triviaal streven.
2, Autoriteit 108%
Dit is een favoriete interviewvraag. Met deze vraag probeert de interviewer erachter te komen hoe goed u het gedrag van objecten begrijpt met betrekking tot constructors, methoden, klassevariabelen (statische variabelen) en instantievariabelen.
import java.util.ArrayList;
import java.util.List;
class Test {
private final List foo;
public Test() {
foo = new ArrayList();
foo.add("foo"); // Modification-1
}
public void setFoo(List foo) {
//this.foo = foo; Results in compile time error.
}
}
In het bovenstaande geval hebben we een constructor voor ‘Test’ gedefinieerd en deze een ‘setFoo’-methode gegeven.
Over constructor:Constructor kan slechts éénkeer per objectcreatie worden aangeroepen door het trefwoord new
te gebruiken. U kunt de constructor niet meerdere keren aanroepen, omdat de constructor daar niet voor is ontworpen.
Over methode:een methode kan zo vaak worden aangeroepen als je wilt (zelfs nooit) en de compiler weet het.
Scenario 1
private final List foo; // 1
foo
is een instantievariabele. Wanneer we een klasseobject Test
maken, wordt de instantievariabele foo
gekopieerd in het object van de klasse Test
. Als we foo
binnen de constructor toewijzen, dan weet de compiler dat de constructor maar één keer wordt aangeroepen, dus er is geen probleem om deze binnen de constructor toe te wijzen.
Als we foo
binnen een methode toewijzen, weet de compiler dat een methode meerdere keren kan worden aangeroepen, wat betekent dat de waarde meerdere keren moet worden gewijzigd, wat niet is toegestaan voor een final
variabele. Dus de compiler besluit dat de constructor een goede keuze is! U kunt slechts één keer een waarde aan een laatste variabele toewijzen.
Scenario 2
private static final List foo = new ArrayList();
foo
is nu een statischevariabele. Wanneer we een instantie van de klasse Test
maken, wordt foo
niet naar het object gekopieerd omdat foo
statisch is. Nu is foo
geen onafhankelijke eigenschap van elk object. Dit is een eigenschap van de klasse Test
. Maar foo
kan worden gezien door meerdere objecten en als elk object dat is gemaakt met behulp van het new
trefwoord, dat uiteindelijk de Test
-constructor zal aanroepen die verandert de waarde op het moment van het maken van meerdere objecten (Onthoud dat static foo
niet in elk object wordt gekopieerd, maar wordt gedeeld tussen meerdere objecten.)
Scenario 3
t.foo.add("bar"); // Modification-2
Boven Modification-2
komt van uw vraag. In het bovenstaande geval wijzigt u niet het eerste object waarnaar wordt verwezen, maar voegt u inhoud toe binnen foo
, wat is toegestaan. Compiler klaagt als u probeert een new ArrayList()
toe te wijzen aan de foo
referentievariabele.
RegelAls u een variabele final
heeft geïnitialiseerd, kunt u deze niet wijzigen om naar een ander object te verwijzen. (In dit geval ArrayList
)
laatsteklassen kunnen niet worden gesubclasseerd
definitievemethoden kunnen niet worden overschreven. (Deze methode is in superklasse)
definitievemethoden kunnen worden overschreven. (Lees dit grammaticaal. Deze methode zit in een subklasse)
Antwoord 3, autoriteit 40%
Laatstezoekwoord kan op verschillende manieren worden gebruikt:
- Een laatste klassekan niet worden gesubklasseerd.
- Een laatste methodekan niet worden overschreven door subklassen
- Een laatste variabelekan maar één keer worden geïnitialiseerd
Ander gebruik:
- Wanneer een anonieme innerlijke klasse wordt gedefinieerd binnen de hoofdtekst van een methode,
alle variabelen die definitief zijn verklaard in het kader van die methode zijn
toegankelijk vanuit de innerlijke klasse
Een statische klassevariabele bestaat vanaf het begin van de JVM en moet in de klasse worden geïnitialiseerd. De foutmelding wordt niet weergegeven als u dit doet.
Antwoord 4, autoriteit 11%
Het final
zoekwoord kan op twee verschillende manieren worden geïnterpreteerd, afhankelijk van waarvoor het wordt gebruikt:
Waardetypes:Voor int
s, double
s enz. zorgt het ervoor dat de waarde niet kan veranderen,
Referentietypen:voor verwijzingen naar objecten zorgt final
ervoor dat de verwijzingnooit verandert, wat betekent dat deze altijd naar hetzelfde zal verwijzen object. Het geeft geen enkele garantie dat de waarden in het object waarnaar wordt verwezen, hetzelfde blijven.
Als zodanig, final List<Whatever> foo;
zorgt ervoor dat foo
altijd verwijst naar dezelfdelijst, maar de inhoudvan die lijst kan in de loop van de tijd veranderen.
Antwoord 5, autoriteit 4%
Als je foo
statisch maakt, moet je het initialiseren in de klassenconstructor (of inline waar je het definieert) zoals in de volgende voorbeelden.
Klasse-constructor (niet instantie):
private static final List foo;
static
{
foo = new ArrayList();
}
Inline:
private static final List foo = new ArrayList();
Het probleem hier is niet hoe de final
modifier werkt, maar eerder hoe de static
modifier werkt.
De final
-modifier dwingt een initialisatie van uw referentie af tegen de tijd dat de aanroep van uw constructor is voltooid (d.w.z. u moet deze initialiseren in de constructor).
Als je een attribuut inline initialiseert, wordt het geïnitialiseerd voordat de code die je voor de constructor hebt gedefinieerd wordt uitgevoerd, zodat je de volgende resultaten krijgt:
- als
foo
static
is, wordtfoo = new ArrayList()
uitgevoerd vóór destatic{}
constructor die u voor uw klasse hebt gedefinieerd, wordt uitgevoerd - als
foo
nietstatic
is, wordtfoo = new ArrayList()
uitgevoerd voordat uw constructor wordt uitgevoerd
Als u een attribuut niet in-line initialiseert, dwingt de final
-modifier af dat u het initialiseert en dat u dit in de constructor moet doen. Als je ook een static
modifier hebt, is de constructor waarin je het attribuut moet initialiseren het initialisatieblok van de klasse: static{}
.
De fout die u in uw code krijgt, is het feit dat static{}
wordt uitgevoerd wanneer de klasse wordt geladen, vóór de tijd dat u een object van die klasse instantieert. Je hebt dus foo
niet geïnitialiseerd wanneer de klas is gemaakt.
Denk aan het static{}
blok als een constructor voor een object van het type Class
. Hier moet u de initialisatie van uw klassekenmerken static final
uitvoeren (indien niet inline gedaan).
Kanttekening:
De final
modifier verzekert alleen stabiliteit voor primitieve typen en referenties.
Als je een final
object declareert, krijg je een final
verwijzingnaar dat object, maar het object zelf is niet constant.
Wat u werkelijk bereikt wanneer u een final
-attribuut declareert, is dat, zodra u een object voor uw specifieke doel declareert (zoals de final List
die u heeft gedeclareerd), dat en alleen dat object zal voor dat doel worden gebruikt: u kunt List foo
niet wijzigen in een andere List
, maar u kunt nog steeds uw List
door items toe te voegen/te verwijderen (de List
die u gebruikt zal hetzelfde zijn, alleen met gewijzigde inhoud).
Antwoord 6, autoriteit 2%
Dit is een zeer goede vraag voor een sollicitatiegesprek. Soms vragen ze je zelfs wat het verschil is tussen een definitief object en een onveranderlijk object.
1) Wanneer iemand een definitief object noemt, betekent dit dat de verwijzing niet kan worden gewijzigd, maar de status (instantievariabelen) kan worden gewijzigd.
2) Een onveranderlijk object is een object waarvan de status nietkan worden gewijzigd, maar waarvan de referentie kan worden gewijzigd.
Bijv.:
String x = new String("abc");
x = "BCG";
ref variabele x kan worden gewijzigd om naar een andere tekenreeks te wijzen, maar de waarde van “abc” kan niet worden gewijzigd.
3) Instantievariabelen (niet-statische velden) worden geïnitialiseerd wanneer een constructor wordt aangeroepen. U kunt dus waarden initialiseren voor uw variabelen binnen een constructor.
4) “Maar ik zie dat je de waarde in de constructor/methoden van de klasse kunt wijzigen”. — Je kunt het niet binnen een methode veranderen.
5) Een statische variabele wordt geïnitialiseerd tijdens het laden van de klas. U kunt dus niet binnen een constructor initialiseren, het moet zelfs ervoor worden gedaan. U moet dus waarden toewijzen aan een statische variabele tijdensdeclaratie zelf.
Antwoord 7, autoriteit 2%
Het final
trefwoord in java wordt gebruikt om de gebruiker te beperken. Het java final
trefwoord kan in veel contexten worden gebruikt. Finale kan zijn:
- variabele
- methode
- klas
Het trefwoord final
kan worden toegepast met de variabelen, een final
-variabele die geen waarde heeft, wordt lege final
-variabele of niet-geïnitialiseerde final
variabele. Het kan alleen in de constructor worden geïnitialiseerd. De lege variabele final
kan ook static
zijn en wordt alleen geïnitialiseerd in het static
-blok.
Java laatste variabele:
Als u een variabele als final
maakt, kunt u de waardevan de final
variabele niet wijzigen (deze zal constant zijn).
Voorbeeld van final
variabele
Er is een laatste variabele snelheidslimiet, we gaan de waarde van deze variabele wijzigen, maar deze kan niet worden gewijzigd omdat de uiteindelijke variabele die eenmaal een waarde heeft gekregen, nooit kan worden gewijzigd.
class Bike9{
final int speedlimit=90;//final variable
void run(){
speedlimit=400; // this will make error
}
public static void main(String args[]){
Bike9 obj=new Bike9();
obj.run();
}
}//end of class
Java laatste les:
Als je een klasse als final
maakt, kun je deze niet verlengen.
Voorbeeld van laatste les
final class Bike{}
class Honda1 extends Bike{ //cannot inherit from final Bike,this will make error
void run(){
System.out.println("running safely with 100kmph");
}
public static void main(String args[]){
Honda1 honda= new Honda();
honda.run();
}
}
Java laatste methode:
Als u een methode definitief maakt, kunt u deze niet overschrijven.
Voorbeeld van final
methode
(run() in Honda kan run() in Bike niet overschrijven)
class Bike{
final void run(){System.out.println("running");}
}
class Honda extends Bike{
void run(){System.out.println("running safely with 100kmph");}
public static void main(String args[]){
Honda honda= new Honda();
honda.run();
}
}
gedeeld van:
http://www.javatpoint.com/final-keyword
Antwoord 8, autoriteit 2%
Het is de moeite waard om enkele duidelijke definities te noemen:
Klassen/Methoden
Je kunt sommige of alle klassenmethoden declareren als
final
, om aan te geven dat de methode niet kan worden overschreven door subklassen.
Variabelen
Als een variabele
final
eenmaal is geïnitialiseerd, bevat deze altijd dezelfde waarde.
final
vermijd in principe overschrijven/superschrijven door iets (subklassen, variabele “opnieuw toewijzen”), afhankelijk van het geval.
Antwoord 9
"A final variable can only be assigned once"
*Reflection*
– “wowo wacht, houd mijn biertje vast”.
Bevriezenvan final
velden gebeurt in twee scenario’s:
- Einde van constructor.
- Als reflectie de waarde van het veld bepaalt. (zo vaak als het wil)
Laten we de wet overtreden
public class HoldMyBeer
{
final int notSoFinal;
public HoldMyBeer()
{
notSoFinal = 1;
}
static void holdIt(HoldMyBeer beer, int yetAnotherFinalValue) throws Exception
{
Class<HoldMyBeer> cl = HoldMyBeer.class;
Field field = cl.getDeclaredField("notSoFinal");
field.setAccessible(true);
field.set(beer, yetAnotherFinalValue);
}
public static void main(String[] args) throws Exception
{
HoldMyBeer beer = new HoldMyBeer();
System.out.println(beer.notSoFinal);
holdIt(beer, 50);
System.out.println(beer.notSoFinal);
holdIt(beer, 100);
System.out.println(beer.notSoFinal);
holdIt(beer, 666);
System.out.println(beer.notSoFinal);
holdIt(beer, 8888);
System.out.println(beer.notSoFinal);
}
}
Uitvoer:
1
50
100
666
8888
Het –finale “-veld is 5 verschillende ” definitief “-waarden toegewezen (Noteer de aanhalingstekens ) . En het kan verschillende waarden over en over hebben toegewezen.
Waarom? Omdat reflectie is als Chuck Norris, en als het de waarde van een geïnitialiseerde laatste veld wil wijzigen, dan is dit. Sommigen zeggen dat hij zelf degene is die de nieuwe waarden in de stapel duwt:
Code:
7: astore_1
11: aload_1
12: getfield
18: aload_1
19: bipush 50 //wait what
27: aload_1
28: getfield
34: aload_1
35: bipush 100 //come on...
43: aload_1
44: getfield
50: aload_1
51: sipush 666 //...you were supposed to be final...
60: aload_1
61: getfield
67: aload_1
68: sipush 8888 //ok i'm out whatever dude
77: aload_1
78: getfield
10
final
is een gereserveerd zoekwoord in Java om de gebruiker te beperken en deze kan worden toegepast op ledenvariabelen, methoden, klasse en lokale variabelen. Definitieve variabelen worden vaak gedeclareerd met de static
trefwoord in Java en worden als constanten behandeld. Bijvoorbeeld:
public static final String hello = "Hello";
Wanneer we de final
trefwoord gebruiken met een variabele aangifte, kan de waarde die is opgeslagen in die variabele niet wordt gewijzigd.
Bijvoorbeeld:
public class ClassDemo {
private final int var1 = 3;
public ClassDemo() {
...
}
}
Opmerking: een klasse die als definitief is gedeclareerd, kan niet worden uitgebreid of geërfd (d.w.z. er kan geen subklasse van de superklasse zijn). Het is ook goed om op te merken dat methoden die als definitief zijn gedeclareerd, niet kunnen worden overschreven door subklassen.
De voordelen van het gebruik van het laatste zoekwoord worden behandeld indeze thread.
Antwoord 11
Stel dat je twee spaarpotten hebt, rood en wit. Je wijst aan deze spaarpotten maar twee kinderen toe en ze mogen hun spaarpot niet verwisselen. Dus je hebt rode of witte spaarpotten (definitief) je kunt de doos niet wijzigen, maar je kunt wel geld op je doos zetten. Het kan niemand iets schelen (Modificatie-2).
Antwoord 12
Lees alle antwoorden.
Er is nog een andere gebruikerssituatie waarbij het trefwoord final
kan worden gebruikt, bijvoorbeeld in een methode-argument:
public void showCaseFinalArgumentVariable(final int someFinalInt){
someFinalInt = 9; // won't compile as the argument is final
}
Kan worden gebruikt voor een variabele die niet mag worden gewijzigd.
Antwoord 13
Als je het statisch definitief maakt, moet het worden geïnitialiseerd in een statisch initialisatieblok
private static final List foo;
static {
foo = new ArrayList();
}
public Test()
{
// foo = new ArrayList();
foo.add("foo"); // Modification-1
}
Antwoord 14
De final
Trefwoord geeft aan dat een variabele slechts één keer kan worden geïnitialiseerd. In uw code voert u alleen één initialisatie van de finale uit, zodat de voorwaarden zijn voldaan. Deze verklaring voert de eenzame initialisatie uit van foo
. Merk op dat final
! = Onveranderlijk, het betekent alleen dat de referentie niet kan veranderen.
foo = new ArrayList();
Wanneer u foo
als static final
De variabele moet worden geïnitialiseerd wanneer de klasse is geladen en kan niet vertrouwen op instantiatie (aka call to constructor) om foo
Omdat statische velden beschikbaar moeten zijn zonder een instantie van een klasse. Er is geen garantie dat de constructeur is gebeld voorafgaand aan het gebruik van het statische veld.
Wanneer u uw methode onder de static final
-cenario uitvoert, wordt de Test
Klasse geladen vóór het instantiëren van t
Op dit moment is er geen instantiatie van foo
wat betekent dat het niet is geïnitialiseerd, dus foo
is ingesteld op de standaard voor alle objecten die null
is. Op dit punt neem ik aan dat uw code een NullPointerException
gooit wanneer u probeert een item aan de lijst toe te voegen.
15
Allereerst, de plaats in uw code waar u initialiseert (d.w.z. toewijzen voor de eerste keer) Foo is hier:
foo = new ArrayList();
foo is een object (met typelijst), dus het is een -referentie type, geen -waarde type (zoals INT). Als zodanig heeft het een verwijzing naar een geheugenlocatie (bijvoorbeeld 0xa7d2a834) waar uw lijstelementen zijn opgeslagen. Lijnen zoals deze
foo.add("foo"); // Modification-1
wijzig de waarde van foo niet (wat wederom slechts een verwijzing is naar een geheugenlocatie). In plaats daarvan voegen ze gewoon elementen toe aan die geheugenlocatie waarnaar wordt verwezen. Als u het zoekwoord laatstewilt schenden, moet u foo opnieuw als volgt opnieuw toewijzen:
foo = new ArrayList();
Dat zoueen compilatiefout opleveren.
Nu, met dat uit de weg, denk eens na over wat er gebeurt als u het statischezoekwoord toevoegt.
Als je het statische sleutelwoord NIET hebt, heeft elk object dat de klasse instantieert zijn eigen kopie van foo. Daarom wijst de constructor een waarde toe aan een lege, nieuwe kopie van de foo-variabele, wat prima is.
Als je echter wel het statische sleutelwoord hebt, bestaat er maar één foo in het geheugen dat aan de klasse is gekoppeld. Als u twee of meer objecten zou maken, zou de constructor elke keer proberen die ene foo opnieuw toe te wijzen, in strijd met het laatstetrefwoord.
Antwoord 16
- Omdat de laatste variabele niet-statisch is, kan deze worden geïnitialiseerd in de constructor. Maar als je het statisch maakt, kan het niet worden geïnitialiseerd door de constructor (omdat constructors niet statisch zijn).
- Toevoeging aan lijst zal naar verwachting niet stoppen met het definitief maken van de lijst.
final
bindt alleen de verwijzing naar een bepaald object. Je bent vrij om de ‘status’ van dat object te veranderen, maar niet het object zelf.
Antwoord 17
Hier volgen verschillende contexten waarin final wordt gebruikt.
Definitieve variabelenEen laatste variabele kan maar één keer worden toegewezen. Als de variabele een referentie is, betekent dit dat de variabele niet opnieuw kan worden gekoppeld om naar een ander object te verwijzen.
class Main {
public static void main(String args[]){
final int i = 20;
i = 30; //Compiler Error:cannot assign a value to final variable i twice
}
}
Definitieve variabele kan later worden toegewezen (niet verplicht om een waarde toe te kennen wanneer deze wordt gedeclareerd), maar slechts één keer.
Eindklassen Een laatste klasse kan niet worden uitgebreid (geërfd)
final class Base { }
class Derived extends Base { } //Compiler Error:cannot inherit from final Base
public class Main {
public static void main(String args[]) {
}
}
Eindmethoden Een definitieve methode kan niet worden overschreven door subklassen.
//Error in following program as we are trying to override a final method.
class Base {
public final void show() {
System.out.println("Base::show() called");
}
}
class Derived extends Base {
public void show() { //Compiler Error: show() in Derived cannot override
System.out.println("Derived::show() called");
}
}
public class Main {
public static void main(String[] args) {
Base b = new Derived();;
b.show();
}
}
Antwoord 18
Vooral zijn correct. Verder, als je niet wilt dat anderen subklassen van je klas maken, verklaar je klas dan als definitief. Dan wordt het het bladniveau van uw klassenboomhiërarchie dat niemand het verder kan uitbreiden. Het is een goede gewoonte om een enorme hiërarchie van klassen te vermijden.