7. előadás
Mutabilitás
Final kulcsszó
Nyilvános, módosíthatatlan belső állapot.
Kitérő: Tömbök
Új, megadott elemű tömböt létre lehet hozni:
final referencia
Egy változó végleges értéke (mint a const C-ben)
final Rational p = new Rational(1, 2); // final **referencia**
p.setNumerator(3); // Ez még lehetséges, mert a referenciát nem írja felül
p = new Rational(1, 4); // Fordítási hiba
A String osztály módosíthatatlan (immutable)
String fortytwo = "42";
String twentyfour = fortytwo.reverse();
String twentyfourhundredfortytwo = twentyfour + fortytwo;
A java.lang.StringBuilder és java.lang.StringBuffer módosítható
StringBuilder sb = new StringBuilder("");
for(char c = 'a'; c <= 'z'; c++){
sb.append(c).append(,);
}
sb.deleteCharAt(sb.length()-1); //Utolsó vessző eltávolítása
String letters = sb.toString();
A char[] is módosítható
String letters = "";
for( char c = 'a'; c <= 'z'; ++c ){
letters += (c + ","); // Mindig egy-egy új Stringet hoz létre
}
letters = letters.substring(0, letters.length()-1);
Procedurális / moduláris stílus
Osztály szintű metódus - függvény
Immutabilis, új objektumot ad vissza
public class Rational {
private final int numerator, denominator;
public Rational( int numerator, int denominator ){ ... }
public int numerator(){ return numerator; }
public int denominator(){ return denominator; }
public static Rational times( Rational left, Rational right )
{
return new Rational( left.numerator * right.numerator,
left.denominator * right.denominator );
}
}
Rational p = new Rational(1,3), q = new Rational(1,2);
Rational r = Rational.times(p,q);
Osztály szintű metódus - eljárás
Mutabilis, a bal objektumot módosítja
public class Rational
{
private int numerator, denominator;
public Rational( int numerator, int denominator ){ ... }
public int getNumerator(){ return numerator; }
public void setNumerator( int numerator ){ ... }
...
public static void multiplyLeftWithRight( Rational left, Rational right )
{
left.numerator *= right.numerator;
left.denominator *= right.denominator;
}
}
Rational p = new Rational(1,3), q = new Rational(1,2);
Rational.multiplyLeftWithRight(p,q);
Paraméterátadás
- Érték szerinti
- Érték-eredmény szerinti
- Cím szerinti
- Megosztás szerinti
.--.
- Szövegszerű helyettesítés
- Eredmény szerinti
- Név szerinti
- Igény szerinti
Paraméterátadás - érték szerinti (call-by-value)
primitív típusú paraméterre
Példa:
Rational p = new Rational(1,3);
int two = 2;
p.setNumerator(two);
println(p); //2/3
System.out.println(two); //2, a `numerator = 0` ellenére is
Paraméterátadás - Megosztás szerinti (call-by-sharing)
referencia típusú paraméterre (a referenciát érték szerint adjuk át)
public static void multiplyLeftWithRight( Rational left, Rational right )
{
left.numerator *= right.numerator;
left.denominator *= right.denominator;
}
Példa:
public static void multiplyLeftWithRight( Rational left, Rational right )
{
left.numerator *= right.numerator; // `left` referencia belső értékét módosítja
left.denominator *= right.denominator;
left = new Rational(9,7); // felülírja a `left` REFERENCIÁT!
}
Rational p = new Rational(1,3), q = new Rational(1,2);
Rational.multiplyLeftWithRight(p,q);
println(p); //1/6. Nem lesz 9/7, mert ott csak a REFERENCIÁT írtuk felül, nem annak az értékét
Változó számú paraméterek
static int sum( int[] nums )
{
int s = 0;
for( int n: nums ){ s += n; }
return s;
}
sum( new int[]{1,2,3,4,5,6} );
Helyette nyelvi elem:
static int sum( int... nums )
{
int s = 0;
for( int n: nums ){ s += n; }
return s;
}
sum( 1,2,3,4,5,6 );
Ez, valójában átfordul a feljebb található kódrészletre.
Belső állapot kiszivárogtatása
public class Rational {
private int[] data;
...
public int getNumerator(){ return data[0]; }
public int getDenominator(){ return data[1]; }
public void set( int[] data ){
if( data == null || data.length != 2 || data[1] <= 0 )
throw new IllegalArgumentException();
this.data = data;
}
}
int[] cheat = {3,4};
Rational p = new Rational(1,2);
p.set(cheat); // betölti a 3/4-et
cheat[1] = 0;
// Mivel a `cheat` referenciaként lett belehelyezve p-be, ezért a felülírás érvényes rá:
System.out.println(p.getDenominator()); // Kimenet: 0
Belső állapot kiszivárogtatása (getterrel)
public class Rational {
private int[] data;
...
public int getNumerator(){ return data[0]; }
public int getDenominator(){ return data[1]; }
public void get(){
return data; // Az `int[]` referenciát adja vissza
}
}
Rational p = new Rational(1,2);
int[] cheat = p.get();
cheat[1] = 0;
System.out.println(p.getDenominator()); // Kimenet: 0
Belső állapot kiszivárogtatása (megoldás)
Defenzív másolás
public class Rational
{
private final int[] data;
public Rational( int[] data )
{
if( data == null || data.length != 2 || data[1] <= 0 )
throw new IllegalArgumentException();
this.data = new int[]{ data[0], data[1] };
}
public void set( int[] data )
{
this.data = new int[]{ data[0], data[1] }
}
public int[] get()
{
return new int[]{ data[0], data[1] };
}
}
Módosíthatatlan objektumokat nem kell másolni
Például: név (Stringként), kor (intként)
public class Person
{
private String name;
public Person(String name){
/* `name` hibaellenőrzése */
this.name = name;
}
public String getName(){return name;}
public void setName(String name){/* Szintén hibaellenőrzés */this.name = name;}
}
Aliasing tömbön belül
Rational rats[2]; // fordítási hiba
Rational rats[] = new Rational[2]; // = {null,null};
Rational[] rats = new Rational[2]; // gyakoribb
rats[0] = new Rational(1,2);
rats[1] = rats[0]; // A tömb két eleme ugyan arra a referenciára mutat
rats[1].setDenominator(3);
System.out.println(rats[0].getDenominator()); // Kimenet: 3
/**
* PRE: rats != null and (j != j => rats[i] != rats[j])
*/
public static void increaseAllByOne( Rational[] rats ){
for(Rational p: rats){
p.setNumerator(p.getNumerator()+p.getDenominator()s);
}
}
Aliasing tömbök tömbjén
Rational half = new Rational(1,2);
Rational[] halves = {half, half};
Rational[][] matrix = {halves, halves, halves};
Lambdák
int[] nats = {0,1,2,3,4,5,6};
int[] nats = new int[1000];
for(int i = 0; i < nats.length; ++i)
{
nats[i] = i;
}
int[] nats = new int[1000];
java.util.Arrays.setAll(nats, i->i);
java.util.Arrays.setAll(nats, i->(int)(100*Math.random()));
public static void main(String[] args){
java.util.Arrays.sort(args);
java.util.Arrays.sort(args, (s, z) -> s.length()-z.length()); // Meg lehet adni, hogy mi alapján legyen rendezve
}
java.util.Arrays.stream(nums)
.filter(i -> i % 2 == 0)
.map(i -> i/2)
.limit(10)
.forEach(i -> System.out.println(i));
Jövőhéten nincs személyes jelenléttel előadás!