Vinnaren i pepparkakshustävlingen!
2018-10-07, 13:08
  #7285
Medlem
kjellbrels avatar
Citat:
Ursprungligen postat av DieTrolle
Sitter med ett litet problem när jag ska skapa en "sentinel" i mitt binära träd. Istället för att löven ska ha null-pekare så ska löven peka på en "sentinel". Men jag är lite osäker på om ett objekt kan/ska refererera tillbaks till sig själv på detta sätt redan i konstruktorn. Det verkar fungera men skulle vilja ha lite åsikter på min lösning.
Nu är jag som vanligt sen i diskussionen, men ifall du ville ha mer åsikter och förtydligande vad som händer, så har jag följande bidrag.

TL;DR-svaret på din fråga är att du är garanterad att tilldelningen av left och right blir null för just det fall du undrar över.

Det längre svaret är att framförallt 2 regler i Java är intressanta för vad som händer här:
R1. Definite assignment rule
R2. Instansvariabler är aldrig oinitierade (vänta med att protestera)

För att förtydliga och resonera runt detta så har jag klippt ned din kod med bara de relevanta delarna och lagt till lite så man kan testköra och se vad som händer också. En rejäl fulmanöver har jag gjort också med klassen S nedan, något som jag aldrig skulle göra annat än i labbkod, men det hjälper för att påvisa vad som sker när man testkör.

Kod:
class S { // Just for inspection purpose!
    S() { // Never ever EVER code like this!
        System.out.println("1. nil: " + ((Tree)this).nil);        
    }
}

public class Tree extends S {
    Node nil = new Node();  // T1
    
    Tree() { // T2
        System.out.println("3. nil: " + nil);        
    }
    
    class Node { // Note: Inner class, not nested!
        Node n;
        
        Node() {
            System.out.println("2. nil: " + nil +
                               "\n   (this: " + this + 
                               ", outer: " + Tree.this + ")");
            n = nil; // T3
        }
    }
    
    public static void main(String[] args) {
        new Tree();
        // Node n;  // T4
        // System.out.println("4. n: " + n);  // Violates definite assignment rule.       
    }
}

T1: Detta är en instansvaribel till Tree med en sk "instance initializer expression". Det senare innebär att initieringsuttrycket kommer utföras som första steg i varje existerande (även eventuell implicit) konstruktor för Tree före dess kodkropp, dvs vid T2 i exemplet.

Notera att initieringsuttrycket körs i sin helhet först och sen sker tilldelningen till vänsterledet. Det får ju effekten i ditt fall att Node-konstruktorn vid T3 refererar till Trees instansvariabel (via outer this) nil innan denna tilldelning (instance initializer) har skett.

Det känns ju som R1 borde träda in här då, som förbjuder all evaluering av variabler som inte är garanterat initierade. Kompilatorn måste enligt Javas språkdefinition söka av alla möjliga exekveringsvägar för att utesluta att detta inte kan ske på något sätt. Kan den inte utesluta detta så måste denna slå ned på det med kompileringsfel.

Men, R2 to the rescue i detta fall. Instansvariabler får alltid ett värde, även före initieringsuttryck i konstruktorer och initializers, deras sk defaultvärden. Det är i princip värdet 0 men i dess motsvarande form för icke taltyper, dvs false för boolean och null för objektreferenser.

R2 garanterar alltså att variabeln nil har värdet null vid T3 och kompilatorn ser att R1 är uppfyllt.

För att se lite tydligare när initializer expression och initieringen till nil sker, så gjorde jag en fulmanöver med klassen S som Tree ärver från samt några numrerade utskrifter av nil i olika skeden av initieringen.

En testkörning ger:
Kod:
1. nil: null
2. nil: null
   (this: Tree$Node@15db9742, outer: Tree@6d06d69c)
3. nil: Tree$Node@15db9742

Som synes körs superklassens konstruktor först (oavsett implicit eller explicit super()-anrop) där man kan se (genom grotesk kodmissbruk) att nil har värdet null (sitt default-state). Sedan sker "initializer expression" och vi ser därmed utskriften från Node-konstruktorn och nil är som väntat null fortfarande. Efter det att hela initializer expression är klar (med tilldelningen också) körs kodkroppen i Trees konstruktor och vi får den tredje utskriften där vi ser att nil nu refererar till ett Node-objekt. Utskriften av this i Node-konstruktorn bekräftar också att det är samma objekt som skapades vid det tillfället.

Om någon då undrar när R1 slår till så är enklaste exemplet stackvariabler. Se T4 och de två bortkommenterade raderna där. Ta bort kommentarerna så ser man att kompilatorn aldrig kommer släppa igenom användandet av n så länge den inte är initierad.

Sen ett litet sidospår som jag inte vet om du känner till eller inte. Var det meningen att Node skulle vara en "inner class" och inte en "nested class"? Det är omöjligt att avgöra på det lilla du postat vad intentionen är, men eftersom det är så vanligt att många nya i Java av misstag använder inner när de ville ha nested, så frågar jag. I just det lilla exempel du har så kommer du förvisso inte åt NIL om den är nested, men om Node påtvingas typkännedom till Tree endast för att lösa åtkomsten till en specifik instans av Node i ditt system, så tycker jag det finns bättre lösningar. Min egen preferens är att alltid minimera typberoenden i alla system, oavsett storlek. Det betalar sig nästan alltid med tiden.
Citera
2018-10-08, 11:59
  #7286
Medlem
Varför ger denna kod svaret 55555 när den ska ge 51234?
Kod:
public class fdssdf {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		int[] mainArray = {1,2,3,4,5};
		int[] newArray = mainArray.clone();
		for (int i = 0; i < mainArray.length; i++) {System.out.print(changePositions(newArray)[i]);}
	}
	public static int[] changePositions(int[] array) {
		
		int temporary = array[array.length - 1];
		for (int i = array.length - 1; i > 0; i--) {
			array[i] = array[i - 1];
		}
		array[0] = temporary;
		return array;
	}
}
Citera
2018-10-08, 12:32
  #7287
Medlem
Citat:
Ursprungligen postat av 1337swish
Varför ger denna kod svaret 55555 när den ska ge 51234?

Prova att skriva ut hela arrayen under varje steg i transformeringen så du ser vad som händer.
__________________
Senast redigerad av Hominem 2018-10-08 kl. 12:43.
Citera
2018-10-08, 12:41
  #7288
Medlem
[quote=Hominem|65475970]
Citat:
Ursprungligen postat av 1337swish
Varför ger denna kod svaret 55555 när den ska ge 51234?[/QUOTE

Prova att skriva ut hela arrayen under varje steg i transformeringen så du ser vad som händer.

fast jag förstår inte varför för att om jag skriver om utskriften och använder mig av Arrays.toString metoden så fungerar det klockrent. Och kan inte se vad jag har missat med den andra koden??
Citera
2018-10-08, 12:46
  #7289
Medlem
kjellbrels avatar
Citat:
Ursprungligen postat av 1337swish
Varför ger denna kod svaret 55555 när den ska ge 51234?
Kod:
	public static void main(String[] args) {
                ...
		for (int i = 0; i < mainArray.length; i++) {
                    System.out.print(changePositions(newArray)[i]);
                }
	}
}
Kolla noga på koden för din utskrift ovan igen och fundera över följande frågor:
1. Hur många gånger kör du changePositions()?
2. Exakt när skriver du ut element 0 respektive element 1 osv?
Citera
2018-10-24, 07:10
  #7290
Medlem
Jag vill göra ett nytt objekt av en klass i en annan klass. Men får ett felmeddelande.

klass 1

import java.*;
public class theGetClass {
public static void main (String [] args) {
student student1 = new student(); //objekt av klass 2
student1.id = 1; //vill nå klass 2 variabler men får felmeddelande på denna rad.
}
}

klass 2

import java.*;
public class student {
public static void main (String [] args) {

int id;
String name;
int phone;
char grade;

}
}


// Felmeddelande: id cannot be resolved or is not a field
Citera
2018-10-24, 10:09
  #7291
Medlem
Citat:
Ursprungligen postat av bosscs2
Jag vill göra ett nytt objekt av en klass i en annan klass. Men får ett felmeddelande.

// Felmeddelande: id cannot be resolved or is not a field

id är en lokal variabel i metoden main och inte ett fält i klassen student i ditt exempel. (Lokala variabler kan inte användas utanför metoden där de är deklarerade.)
Citera
2018-10-24, 20:28
  #7292
Medlem
Citat:
Ursprungligen postat av Hominem
id är en lokal variabel i metoden main och inte ett fält i klassen student i ditt exempel. (Lokala variabler kan inte användas utanför metoden där de är deklarerade.)

Tack det löste sig.
Citera
2018-11-02, 18:30
  #7293
Medlem
/*Jag försöker mig på polymorfism i java... går väl sådär...
Klass 1 (huvudklassen)*/

import java.*;
public class Calc {
public void eat () {

System.out.println("This Calc is good!");
}

public static void main (String [] args) {

Calc calc = new Calc();
Potpie potpie = new Potpie();
Tuna tuna = new Tuna ();

Calc array1[]= new Calc[0];
array1[1] = new Potpie();
array1[2] = new Tuna();

for(int x = 0 ; x < array1.length; x++) {
System.out.println(array1[x]);
}


}
}


//Andra klassen

public class Potpie extends Calc {
public void eat () {
System.out.println("This potpie is good!");
}
}

//Tredje klassen

public class Tuna extends Calc {
public void eat () {
System.out.println("This Tuna is good!");
}
}


/* Vill göra en array genom alla metoder för att visa på ändringarna
i mina klass metoder. mitt felmeddelande blir:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1
at Calc.main(Calc.java:15)

MIN FRÅGA: VAD ÄR FEL?
*/
Citera
2018-11-02, 18:47
  #7294
Moderator
Neksnors avatar
Citat:
Ursprungligen postat av bosscs2
/*Jag försöker mig på polymorfism i java... går väl sådär...
Klass 1 (huvudklassen)*/

import java.*;
public class Calc {
public void eat () {

System.out.println("This Calc is good!");
}

public static void main (String [] args) {

Calc calc = new Calc();
Potpie potpie = new Potpie();
Tuna tuna = new Tuna ();

Calc array1[]= new Calc[0];
array1[1] = new Potpie();
array1[2] = new Tuna();

for(int x = 0 ; x < array1.length; x++) {
System.out.println(array1[x]);
}


}
}


//Andra klassen

public class Potpie extends Calc {
public void eat () {
System.out.println("This potpie is good!");
}
}

//Tredje klassen

public class Tuna extends Calc {
public void eat () {
System.out.println("This Tuna is good!");
}
}


/* Vill göra en array genom alla metoder för att visa på ändringarna
i mina klass metoder. mitt felmeddelande blir:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1
at Calc.main(Calc.java:15)

MIN FRÅGA: VAD ÄR FEL?
*/
MIN FRÅGA: VILKEN RAD ÄR RAD 15?

Gissar på "array1[1] = new Potpie();" och rekommenderar https://docs.oracle.com/javase/tutor...ts/arrays.html
Citera
2018-11-02, 19:38
  #7295
Medlem
Citat:
Ursprungligen postat av Neksnor
MIN FRÅGA: VILKEN RAD ÄR RAD 15?

Gissar på "array1[1] = new Potpie();" och rekommenderar https://docs.oracle.com/javase/tutor...ts/arrays.html

rad 15 = array1[1] = new Potpie();
Citera
2018-11-02, 20:18
  #7296
Moderator
Neksnors avatar
Citat:
Ursprungligen postat av bosscs2
rad 15 = array1[1] = new Potpie();
Jaha, felmeddelandet säger att du med indexvärdet 1 gick över en gräns. Hur ser den där "array1" ut?Vad vet du om den när du befinner dig på rad 14, redo att ta språnget till rad 15?
Citera

Stöd Flashback

Flashback finansieras genom donationer från våra medlemmar och besökare. Det är med hjälp av dig vi kan fortsätta erbjuda en fri samhällsdebatt. Tack för ditt stöd!

Stöd Flashback