Saturday, April 11, 2020

Java 14'de instanceof Kullanımı

Çok şekillilik, Nesneye Dayalı Programlamanın en önemli mekanizmasıdır. Aşağıdaki örnekte çok şekilli bir yapı oluşturulmuştur:

class A {
}

class B extends A {
}

class C extends A  implements X {
}

class D extends B implements  Z {
}

interface X {}
interface Y {}
interface Z extends X,Y {}

Bu oluşturulan yapıyı UML sınıf diyagramında aşağıdaki şekilde gösterebiliriz:
Şimdi bu yapıyı kullanarak bir kaç nesne yaratalım ve bu nesneleri kullanmak üzere referans değişkenler tanımlayalım:

A a1 = new A();
A a2 = new B();
A a3 = new C();
A a4 = new D();
B b1 = new B();
B b2 = new D();
C c = new C();
D d = new D();

Çok şekilliliğin kuralları gereğince
  • A tipinden bir referans A, B, C ve D tiplerinden nesnelere referans edebilir.
  • B tipinden bir referans B ve D tiplerinden nesnelere referans edebilir.
  • C tipinden bir referans ancak C tipinden bir nesneye referans edebilir.
  • D tipinden bir referans ancak D tipinden bir nesneye referans edebilir.
Çok şekillilik çalışma zamanı ile ilgili bir mekanizmadır. Dolayısı ile referanslar arasında atama yaparken derleyici herhangi bir statik kontrol yapmaz, yapamaz:

A a1 = new A();
A a2 = new B();
A a3 = new C();
A a4 = new D();
D d1= (D) a1;
D d2= (D) a2;
D d3= (D) a3;
D d4= (D) a4;

Yukarıdaki örnekte aslında derleyici statik bir analiz yapmış olsaydı d1, d2 ve d3 değişkenlerine olan atamaların çalışma zamanında ClassCastException fırlatacağını ve sorunlu olduğu uyarısında bulunabilirdi. Ancak derleyici bu analizi yapmaz çünkü gerçekte nesnenin tipi çalışma zamanında bir veri tabanı sorgusu, kullanıcı seçimi ya da web servisi çağrısı gibi işlemlerin sonucunda dinamik olarak belirlenir. Yürütme zamanında, derleyicinin ürettiği kod, atama işlemlerinin uygun olup olmadığını, tip dönüşümünün geçerliliğini sınar ve dönüşüm uyumlu tipler arasında değilse ClassCastException fırlatır. ClassCastException bir RuntimeException sınıfıdır ve fırlatıldığında uygulamanın sonlanmasına neden olur. Bu tür bir hatadan kaçınmak için atamanın öncesinde tip dönüşümünün güvenli olup olmadığının testini yapmak uygun olur. Bu amaçla instanceof operatöründen yararlanılır:

D d1 = null;
if(a1 instanceof D)
  d1 = (D) a1;

Java 14 yukarıdaki kod ile yapılmak istenen işlemi daha yalın bir şekilde ifade etmemize olanak sağlıyor:

if(a1 instanceof D d1) {
          
}

Burada referans değişkeni kullanarak daha karmaşık koşullar oluşturulabilinir:

if(a1 instanceof D d1 && Objects.nonNull(d1) && d1 instanceof X) {

 }

Şimdi instanceof operatörünün bir başka kullanımını görelim:
public class Customer {
    private String identity;
    private String fullname;
    private String email;
    private String phone;

    public Customer(String identity, String fullname, String email, String phone) {
        this.identity = identity;
        this.fullname = fullname;
        this.email = email;
        this.phone = phone;
    }

    @Override
    public boolean equals(Object o) {
        if (o == null) return false;
        if(o instanceof Customer){
            Customer cust = (Customer) o;
            if (!cust.identity.equals(identity)) return false;
            if (!cust.fullname.equals(fullname)) return false;
            if (!cust.email.equals(email)) return false;
            if (!cust.phone.equals(phone)) return false;
        }
        return true;
} . . . }

Customer sınıfı içindeki equals() metodunu instanceof operatörünü kullanarak yeniden tanımlayalım:

public class Customer {
    private String identity;
    private String fullname;
    private String email;
    private String phone;

    public Customer(String identity, String fullname, String email, String phone) {
        this.identity = identity;
        this.fullname = fullname;
        this.email = email;
        this.phone = phone;
    }

    @Override
    public boolean equals(Object o) {
        return o instanceof Customer cust && Objects.nonNull(cust)
                && cust.identity.equals(identity)
                && cust.fullname.equals(fullname)
                && cust.email.equals(email)
                && cust.phone.equals(phone);
    }

    . 
    .
    .

}

No comments:

Post a Comment