Bu dersimizde, önceki derslerimizde üzerinden geçtiğimi erişim tanımlayıcıları-düzenleyicileri (access modifiers) üzerinde daha detaylı bir çalışma yapacağız.

4 adet access modifiers bulunmaktadır.

■ public
■ protected
■ default
■ private

Bir sınıf tanımlarken bunlardan sadece ikisini kullanabilirsiniz. Eğer protected, default(belirtilerek yazılırsa) ve private anahtar kelimelerini sınıf tanımlamalarında kullanırsanız, derleyici(compiler) size “remove invalid modifiers” hatası dönecektir. Az önce parantez açtığım yeri belirtmek gerekirse, sınıf tanımlamalarında “default” anahtar kelimesi bulunmamaktadır. Bu erişimi kullanabilmek için, herhangi bir tanım yapımadan kullanılması gerekmektedir.
Örneğin

default class Test {
  1.  
  2. }

Yerine

class Test {
  1.  
  2. }

bu şekilde kullanmak doğru olandır. Zaten aksi halde “remove invalid modifiers” hatası alınacaktır. Default erişimi ile protected erişim seviyeleri aynı özelliktedir fakat default erişim seviyesini kullanmak için erişim seviyesi belirtilmemesi, bu sayede varsayılan erişim seviyesinin seçilmesi sağlanacaktır.

Erişim kontrollerinde, iki önemli durum vardır.

1 ) Bir sınıfın içindeki bir kod parçacığının (Örneğin methodun) bir başka sınıfa erişimi
2 ) Kalıtım yoluyla erişim.

İlkinde, bir methoda ya da değişkene erişim sağlanırken “.” (Nokta) kullanılır. Örneğin,

class Zoo {
  1.  public String coolMethod() {
  2.      return "Wow baby";
  3.  }
  4. }
  5.  class Moo {
  6.   public void useAZoo() {
  7.       Zoo z = new Zoo();
  8.       System.out.println("A Zoo says, " + z.coolMethod());
  9.  }
  10. }

yukarıdaki gibi. “z.coolMethod()” cümleciğinde nokta ile bir başka sınıfın koduna erşiim sağlanmış oldu.

Şimdi ikinci durumu inceleyelim. İkinci örnekte bir süper sınıf, bir de alt sınıf bulunacak. Alt sınıf, süper sınıftan kalıtıldığı için alt sınıf süper sınıfın bazı özelliklerini kullanacak. Bknz:

class Zoo {
  1.    public String coolMethod() {
  2.    return "Wow baby";
  3.  }
  4. }
  5. class Moo extends Zoo {
  6.    public void useMyCoolMethod() {
  7.         System.out.println("Moo says, " + this.coolMethod());
  8.         Zoo z = new Zoo();
  9.         System.out.println("Zoo says, " + z.coolMethod());
  10.  }
  11. }

Public Members

Bir method ya da değişken public olarak tanımlandığında, paket tanımlamalarından bağımsız olarak proje içerisindeki tüm sınıflar tanımlanan method ya da değişkene erişebilirler. ( Sınıfın erişilebilirliği göz ardı edildiğinde)

package book;
  1. import cert.*;
  2. class Goo {
  3.  public static void main(String[] args) {
  4.  Sludge o = new Sludge();
  5.  o.testIt();
  6.  }
  7. }
  8. // Diğer sınıf
  9. package cert;
  10. public class Sludge {
  11.  public void testIt() { System.out.println("sludge"); }
  12. }

Gördüğünüz gibi farklı paketlerde olmalarına rağmen herhangi bir erişim sorunu yaşanmamakta çünkü “public” erişim seviyesine sahip.

Şimdi gelin bir başka örneği inceleyelim.

package cert;
  1. class Roo {
  2.  public String doRooThings() {
  3.  // imagine the fun code that goes here
  4.  return "fun";
  5.  }
  6. }
  7.  
  8. package notcert; //Not the package Roo is in
  9. import cert.Roo;
  10. class Cloo extends Roo {
  11.  public void testCloo() {
  12.  System.out.println(doRooThings());
  13.  }
  14. }

Burada doRooThings() yordamı public olmasına rağmen, sınıflar farklı paketlerde olduğu için ve sınıfların erişim seviyesi varsayılan (default) sınıfların birbirlerine erişimi yoktur. Bu sebeple, doRooThings() çalışmayacağı için hata alınacaktır fakat Roo sınıfının erişim seviyesini default ‘dan public’e taşırsanız, kod çalışacak ve herhangi bir sorun yaşanmayacaktır.

Private Members

Bir sınıf eğer private anahtar kelimesi ile işaretleniyorsa, o sınıf başka hiçbir kod tarafından erişilemez ve çağrılamaz. Yukarıdaki Roo sınıfı üzerinde biraz değişiklik yapalım.

package cert;
  1. public class Roo {
  2.  private String doRooThings() {
  3.  return "fun";
  4.  }
  5. }

doRooThings() methodu private olarak işaretlendiği için başka hiçbir yerden çağrılamaz, çalıştırılamaz. Eğer çağırmaya kalkarsak, aşağıdaki sorunla karşılaşırız.

package notcert;
  1. import cert.Roo;
  2. class UseARoo {
  3.  public void testIt() {
  4.  Roo r = new Roo(); //Bu kisim mumkun, Roo sinifi public olarak işaretlenmiş
  5.  System.out.println(r.doRooThings()); //derleyici hatası alinicaktir
  6.  }
  7. }

Peki ya bir subclass(alt sınıf) üst sınıfta bulunan private olarak işaretlenmiş herhangi bir sınıf üyesine erişmek isterse ne olur? Şimdiden söyleyebiliriz ki, bu mümkün değildir. Alt sınıf, üst sınıfın private olarak işaretlenmiş herhangi bir üyesine erişemez.

package com.umitsamimi.test.privatevariables;
  1.  
  2. public class Car {
  3.  
  4.  private String modelName;
  5.  public Integer modelYear;
  6.  
  7.  public void setModelName(String modelName) {
  8.   this.modelName = modelName;
  9.  }
  10.  
  11.  public String getModelName() {
  12.   return modelName;
  13.  }
  14. }

Yukarıdaki sınıf, süper olarak kullanılacak ve bir başka sınıf, bu Car isimli sınıftan extend edilecek.

package com.umitsamimi.test.privatevariables;
  1.  
  2. public class BMW extends Car{
  3.  
  4.  public void test()
  5.  {
  6.   modelYear = 1996;
  7.   modelName = "A 116"; // ERROR : Change visibility of "modelName" to protected
  8.  }
  9. }

modelYear değişkenine, BMW sınıfı erişmekte sorun yaşamıyorken, modelName değişkeninin altını çizecektir ve derleyici size “ERROR : Change visibility of “modelName” to protected” mesajını iletecektir.

Kalıtım yoluyla dahi olsa, aynı pakette yer alsalar dahi, private olarak işaretlenen bir üye, bir başka sınıftan ya da yerden erişim sağlayamaz. Protected olarak işaretlenen bir üye, farklı bir pakette olsa dahi(import edildikten sonra) üst sınıftan protected değişkene erişim sağlayabilir fakat private için bu mümkün değildir.

Peki private olarak işaretlenen herhangi bir method subsclass tarafından overriden edilebilir mi? Biraz tuhaf bir soru fakat teknik olarak mümkün değil. Şimdiye kadar gördüğümüze göre alt sınıflar private ile işaretlenen üyeleri kalıtım yoluyla alamıyorlar bu sebeple override edemezler.

Override işlemi olabilmesi için kalıtım(inheritance) olmak zorundadır.

Bu konuyu önümüzdeki bölümlerde detaylıca işleyeceğiz fakat şuan private ile işaretlenen üyelerin kalıtılamayacağı için, override işlemi yapılamayacağı bilinmelidir.

Protected and Default Members

protected erişim seviyesi ile default arasında tek bir farklılık dışında, her şey tamamen aynıdır. Varsayılan (default) erişim seviyesine ancak aynı paketteki sınıflar tarafından erişim sağlanabilirken, protected olarak işaretlenen herhangi bir sınıf üyesine kalıtım yoluyla farklı sınıflardan da erişim sağlanabilir.

Örneğin

package com.umitsamimi.test.privatevariables;
  1.  
  2. public class Car {
  3.  
  4.  private String modelName;
  5.  public Integer modelYear;
  6.  protected Integer price;
  7.  Integer speedLimit;
  8. }

Burada 4 farklı erişim seviyesi bulunmaktadır. Kendisinden kalıtılan fakat farklı pakette bulunan bir alt sınıftan bu değişkenleri birlikte çağıralım

package com.umitsamimi.test.other;
  1. import com.umitsamimi.test.privatevariables.Car;
  2. public class Mercedes extends Car{
  3.  
  4.  public void test()
  5.  {
  6.   modelName ="Mercedes"; // ERROR
  7.   modelYear = 3;
  8.   price = 50000;
  9.   speedLimit =220;// ERROR
  10.  }
  11. }

modelName private olduğu için erişim sağlanamayacaktır. speedLimit değişkeni de varsayılan erişim seviyesinde olduğu için erişim sağlanamayacaktır fakat protected olmasına rağmen price değşikenine, farklı paketten erişim sağlanabilecektir. Sebebi ise, kalıtım(inheritance) dır.

Şimdi aynı şekilde method üzerinden konuyu yeniden değerlendirelim

package certification;
  1. public class OtherClass {
  2.  void testIt() { // herhangi bir belirteç olmaması, bunun default olduğunu gösterir
  3.  System.out.println("OtherClass");
  4.  }
  5. }

Diğer sınıfımız

package somethingElse;
  1.  
  2. import certification.OtherClass;
  3.  
  4. public class AccessClass {
  5.  
  6.  static public void main(String[] args) {
  7.   OtherClass o = new OtherClass();
  8.   o.testIt(); //Error
  9.  }
  10.  
  11. }

Yine burada, varsayılan erişim seviyesine sahip olan bir metoda, farklı bir paketten erişim sağlandığı için hata alınacaktır. (o.testIt(); )

Tekrar altını çizmek gerekirse, default ile protected erişim seviyeleri arasındaki tek fark kalıtımdır. Protected olarak tanımlanan herhangi bir sınıf üyesi, farklı paketlerde olup olmadığına bakılmaksızın, kalıtılan sınıf tarafından kullanılabiliyorken, varsayılan erişim seviyesine sahip bir sınıf üyesi, kalıtılsa dahi kullanılamaz.

Bu konuda son değinilecek yer, varsayılan erişim seviyesindeki sınıf üyesinin, aynı pakette içerisinde alt sınıflara kalıtılabileceğidir.

Örneğin

package com.umitsamimi.test.privatevariables;
  1.  
  2. public class Car {
  3.  
  4.  private String modelName;
  5.  public Integer modelYear;
  6.  protected Integer price;
  7.  Integer speedLimit;
  8. }

Yine üst sınıfımız Car sınıfı olsun ve hemen bir alt sınıf oluşturalım.

package com.umitsamimi.test.privatevariables;
  1.  
  2. public class BMW extends Car{
  3.  
  4.  public void test()
  5.  {
  6.   modelYear = 1996;
  7.   speedLimit = 19;
  8.  }
  9. }

BMW sınıfı, speedLimit değişkenine erişim sağlayabilir. Car sınıfından kalıtılan varsayılan erişim seviyesine sahip speed limit aynı paketlerde olduğu sebebiyle kullanılması tamamen legaldir.

Protected

Yukarıda protected ile varsayılan erişim seviyesi hakkında genel bilgileri paylaşmıştık. Bu bölümde bir kaç detaya göz atacağız.

Protected ile işaretlenmiş bir sınıf üyesine, aynı pakette bulunan diğer sınıfların erişebileceği gibi, farklı pakette olsa dahi, süper sınıftan kalıtılan sınıf da erişebilir demiştik ama ya kalıtım yoluyla erişim yerine referans yoluyla, protected sınıf üyesine erişilmek istenirse?

Hemen bir örnek ile inceleyelim. Elimizde bir tane Süper sınıf olan Parent olsun

package certification;
  1.  
  2. public class Parent {
  3.  protected int x = 9; // protected access
  4. }

Gördüğünüz üzere süper sınıfın içerisinde bulunduğu paketin adı “certification” . Şimdi bir başka paketin altına, Parent sınıfından kalıtılan bir sınıf oluşturalım

package somethingElse;
  1.  
  2. import certification.Parent;
  3.  
  4. class Child extends Parent {
  5.  public void testIt() {
  6.   System.out.println("x is " + x); // Sorun yok kalıtım yoluyla erişebilir.
  7.  
  8.   Parent p = new Parent(); //  Şimdi de referans yoluyla erişmeyi deneyelim
  9.   System.out.println("X in parent is " + p.x); // Ooppps… ! Compiler  error!
  10.  }
  11. }

Child sınıfımız somethingElse paketinin altında. Yine de Parent sınıfının, protected değişkenlerine erişebilir öyle değil mi? Tabi ki erişir, eğer kalıtım yoluyla erişmeyi denerse ama referans yoluyla erişmek isterse, hata alır.

Özetle

Erişilebilirlik                                                          public            protected         default         private
Aynı sınıftan                                                               Erişebilir          Erişebilir             Erişebilir        Erişebilir
Aynı paket içerisinde herhangi bir sınıftan            Erişebilir          Erişebilir             Erişebilir        Erişemez
Alt sınıftan aynı paket içerisinde                             Erişebilir          Erişebilir             Erişebilir        Erişemez
Alt sınıftan farklı paketlerden                                  Erişebilir          Erişebilir             Erişemez        Erişemez

 

 

Nonaccess Member Modifiers

Şimdiye kadar sınıf üyelerine erişim tanımlamaları ile ilgilendik. Bunların yanında erişim izni olmayan tanımlayıcılar var (Nonaccess member modifiers). Dhaa önce bunlar arasından final ve abstract üzerinden biraz geçmiştik. Şimdi de transient, synchronized, native, strictfp anahtar kelimeleri üzerinde duracağız ama en çok static anahtar kelimesine vakit ayıracağız.

Final

Final anahtar kelimesi yordamlar(method) için kullanıldığında genellikle amacı alt sınıf tarafından “override” edilmesinin engellenmek istenmesidir. Bir örnekle açıklayalım, neden Üst sınıfın bir metodunun override edilmesi istenmeyebileceğini. Bir sınıfınız olsun ve bu sınıf Thread sınıfından extend ediliyor olsun. Thread sınıfı içerisindeki isAlive() metodu ile de hala durumun akitf olup olmadığını kontrol etmek istiyorsunuz fakat isAlive() yordamı düzgün override edilmediği için (ki siz tam olarak düzgün override edemeyebilirsiniz) istenildiği gibi çalışmıyor. Bu tür durumların önüne geçmek için final anahtar sözcüğü ile methodların override edilmesini engelleyebilirsiniz.

Benzer durum String sınıfı için de geçerlidir. Siz String sınıfının metodlarını rahatlıkla kullanabilirsiniz ama override edemezsiniz.

Örneğin SuperClass isimli bir sınıfımız olsun.

class SuperClass{
  1.  public final void showSample() {
  2.  System.out.println("One thing.");
  3.  }
  4. }

Aynı şekilde SubClass isimli, SuperClass’dan extend edilen bir alt sınıfımız olsun.

class SubClass extends SuperClass{
  1.  public void showSample() { // süper sınıftan edinilen metodu override etmeyi deneyin
  2.  System.out.println("Another thing.");
  3.  }
  4. }

Aşağıdaki şekilde hata alacaksınız

%javac FinalTest.java
  1. FinalTest.java:5: The method void showSample() declared in class
  2. SubClass cannot override the final method of the same signature
  3. declared in class SuperClass.
  4. Final methods cannot be overridden.
  5.  public void showSample() { }
  6. 1 error

Final Arguments

Method (yordam) argümanları parantez içerisinde tanımlamaları yapılan argümanlardır. Örneğin

public Record getRecord(int fileNumber, int recNumber) {}
  1. </pre>
  2. Method argümanları genellikle local(yerel) değişkenler gibidirler. Yukarıda örneği verilen fileNumber ve recNumber aslında "local variables" kurallarına uygun davranır. Bunun bir anlamı da bu değişkenleri "final" anahtar kelimesi ile işaretleyebilirsiniz.
  3.  
  4. Örneğin
  5. <pre lang="java">public Record getRecord(int fileNumber, final int recordNumber) {}

Fakat yukarıdaki örnekte final olarak tanımlanan recordNumber değişkenin içeriği değiştirilemez. Örneğin

public int finalArgumentMethod(final int number){
  1.   number = number+3;
  2.   return number;
  3.  }

Gibi bir method yazdığınızda, derleyici size — |remove “final” modifier of “number” | — şeklinde bir uyarıda bulunacaktır.

Abstract Methods

Abstract methodları öyle methodlardır ki, tanımlamalarının yapıldıkları sınıfta implementasyonları bulunmaz. Diğer bir deyişle bu metodların fonksiyonel kodları yoktur. Aç küme kapa küme parantez yerine, tanımlama sonuna noktalı virgül konulur. Abstract sınıflarda tanımlanan abstract metodlar, kendisinden kalıtılan alt sınıfların, bu metodları implemente etmelerini mecbur kılar. Abstract olmayan bir sınıfta da abstract metod tanımlanamaz.

Örneğin,

package com.umitsamimi.abstractexample;
  1.  
  2. public class IllegalClass {
  3.  public abstract void doIt();
  4. }

Burada derleyici size, bu metodun hata aldığını söyler ve “abstract” anahtar kelimesini kaldırmanız gerektiğini söyler. Doğru kullanım ise aşağıdaki gibidir.

public abstract class LegalClass{
  1. public abstract void doIt();
  2.  }

Diğer önemli bir nokta ise, abstract sınıflarda yer alan abstract methodlar, kendilerinden extends edilen sınıflarda mutlaka implemente edilmek zorundadır, eğer kalıtılan sınıf bir başka abstract sınıf değilse.

Örneğin, elimizde aşağıdaki gibi bir abstract sınıf olsun.

package com.umitsamimi.abstractexample;
  1. public abstract class TopSuperClass {
  2.  
  3.  public abstract void topSuperMethod();
  4.  
  5.  public void topUnecessaryMethod(){
  6.   // do something
  7.  }
  8. }

Bu sınıf içerisinde iki adet method bulunmaktadır. Biri abstract, öbürü değil. TopSuperClass sınıfından kalıtılan(extends edilen) herhangi bir sınıf topSuperMethod() metodunu mutlaka kendi sınıfında implemente etmesi gerekmektedir. Aksi durumda hata alır. Bu kesin kaideyi bozan tek bir husus vardır, kalıtılan sınıfın abstract olması. Örneğin aşağıdaki gibi.

package com.umitsamimi.abstractexample;
  1.  
  2. public abstract class SuperAbstractClass extends TopSuperClass {
  3.  
  4.  abstract void superMethod();
  5.  
  6.  public void unNecessaryMethod(){
  7.  
  8.  }
  9. }

Gördüğünüz gibi kalıtılan sınıf abstract olduğu için derleyici herhangi bir şekilde size müdahale etmeyecektir fakat SuperAbstractClass sınıfından kalıtılan herhangi bir abstract olmayan sınıf, hem TopSuperClass sınıfının hem de SuperAbstractClass sınıfının soyut(abstact) methodlarını implemente etmek zorundadır. Aşağıda olduğu gibi.

package com.umitsamimi.abstractexample;
  1.  
  2. public class SubClass extends SuperAbstractClass{
  3.  
  4.  @Override
  5.  public void topSuperMethod() {
  6.   // TODO Auto-generated method stub
  7.  
  8.  }
  9.  
  10.  @Override
  11.  void superMethod() {
  12.   // TODO Auto-generated method stub
  13.  
  14.  }
  15.  
  16. }

Bir diğer önemli nokta ise abstract bir method hiçbir şekilde “Final” olarak işaretlenemez. Kalıtılması amacıyla oluşturulan yapının başına “Final” koyamazsınız. Ya da aynı şekilde private da olamaz ama default veya protected olabilir.

Farklı paketlerde dahi olsa, protected olarak işaretlenen methodlara kalıtım vasıtasıyla erişilebilir fakat default erişim seviyesinde bulunan abstract metodlara erişilemez.

Örneğin;

package com.umitsamimi.abstractexample;
  1.  
  2. public abstract class TopSuperClass {
  3.  
  4.  protected abstract void topSuperMethod();
  5.  
  6.  public void topUnecessaryMethod(){
  7.  
  8.  }
  9. }

Burada süper abstract sınıfımız var ve gördüğünüz gibi abstract metodu protected olaran işaretlenmiş. Gelelim alt sınıfımıza.

package com.umitsamimi.finalexample;
  1.  
  2. import com.umitsamimi.abstractexample.TopSuperClass;
  3.  
  4. public class Test extends TopSuperClass {
  5.  
  6.  @Override
  7.  protected void topSuperMethod() {
  8.   // TODO Auto-generated method stub
  9.  }
  10. }

Bu gayet legal bir kullanımdır.

Son olarak abstract metodlar static olarak da tanımlanamazlar.

Synchronized Methods

synchronized anahtar kelimesi, thread erişim zamanında sadece 1 threadin erişebilmesi için kullanılır fakat bu anahtar kelimesi değişkenler için veya sınıf tanımlamalarında kullanılamaz. synchronized anahtar kelimesi sadece methodlar için vardır. Klasin kullanımı aşağıdaki gibidir

public synchronized void methodName(int id) { }
  1. </pre>
  2. <h2>Variable Argument Lists Methods (var-args)</h2>
  3. Bir metodun kaç adet parametre alacağı belirsiz olduğu durumlardır. Örneğin
  4. <pre lang="java">void doStuff(intx) { } // 0 'dan başlayarak sayısız sayıda int türünden parametre beklemektedir
  5.  
  6. void doStuff2(char c, intx) { }  //ilk parametreyi char olarak bekleyip, diğer  girilen tüm parametrelerin  int türünden olması beklenir
  7.  
  8. void doStuff3(Animal… animal) { } //0'dan başlayarak sayısız sayıda Animal türünden parametre beklemektedir.

İllegal kullanımda aşağıdaki gibidir.

void doStuff4(int x…) { } // bad syntax
  1. void doStuff5(intx, chary) { } // too many var-args
  2. void doStuff6(Strings, byte b) { } // var-arg must be last

Constructor Tanımlamaları

Her yeni obje yaratıldığında, javada Constructor (yapıcı) method çağrılır. Siz bir Constructor method tanımlamasanız dahi, derleyici sizin yerinize varsayılan bir Constructor oluşturur. Detaylarını önümüzdeki derslerde işleyeceğiz fakat genel bir bakışla üzerinedn geçelim.

class Foo {
protected Foo() { } // Foo sınıfının Constructor’ı.
protected void Foo() { } // kötü isimlendirme fakat legal (Constructor olarak kullanılamaz, method olarak kullanılabilir.
}

Constructor asla ve asla geri dönüş değerine (return type) sahip olamaz. İkinci methodun legal olmasına rağmen Constructor olmamasının sebebi budur. Constructor herhangi bir erişim seviyesine sahip olabilir, argüman alabilir ama geri dönüş değeri olamaz.

Constructor ‘larda bilmemiz gereken en önemli kural, bir Constructor kesinlikle sınıf adı ile aynı isme sahip olmasıdır. Aynı şekilde Constructor method asla ve asla static olamaz. Final ya da abstract da olamaz.

Aşağıda legal ve illegal kullanımlara örnekleri paylaşıyorum.

class Foo2 {
  1.  // legal constructors
  2.  Foo2() { }
  3.  private Foo2(byte b) { }
  4.  Foo2(int x) { }
  5.  Foo2(int x, inty) { }
  6.  // illegal constructors
  7.  void Foo2() { } // bu bir method, geri dönüş değeri olması sebebiyle constructor olamaz
  8.  Foo() { } // isimler eşleşmediğinden constructor değil.  İsmi Foo2 olsaydı constructor olurdu
  9.  Foo2(short s); // aç küme kapa küme parantezi olmadığı için abstract methoda benzer, bu sebeple constructor değil
  10.  static Foo2(float f) { } // constructor static olamaz
  11.  final Foo2(long x) { } // constructor final olamaz
  12.  abstract Foo2(char c) { } // constructor abstact olamaz
  13.  Foo2(intx, int t) { } // yanlı var-arg synta kullanımı. (int x, int …t) şeklinde olmalıydı
  14.  }

Sınıf üyelerinin tanımlanmaları Birinci bölüm burada son bulmuştur. İkinci bölüm için tıklayınız



*** *** Rica*** ***

Merhaba, cep telefonları için bir uygulama yazdım. Uygulamamın başarılı olması için onu android marketten indirir misiniz? Kesinlikle virüs ya da benzeri tehlikeler içermemektedir.
Aslında faydasız bir uygulama da değil. Allah korusun, acil durumlarda kan ararsanız eğer, şehre ve kan grubuna göre kan arama uygulaması. indirmek için lütfen : tıklayınız

*** *** Rica*** ***