Java'da sınıf değişkenlerini geçersiz kılmanın bir yolu var mı?


161
class Dad
{
    protected static String me = "dad";

    public void printMe()
    {
        System.out.println(me);
    }
}

class Son extends Dad
{
    protected static String me = "son";
}

public void doIt()
{
    new Son().printMe();
}

"Baba" işlevi yazdırılacaktır. "Oğul" baskısı yapmanın bir yolu var mı?


111
Korumalı bir statik görürseniz çalıştırın.
Tom Hawtin - tackline

23
@ TomHawtin-tackline cehaletimi affeder, ancak korunan bir statik neden kaşlarını çattı? Google'ı denedim ama net bir cevap bulamıyorum. Teşekkürler
Tony Chan

16
Bu soruyu kontrol edin: Neden
Java'da

Yanıtlar:


68

Evet. Ancak değişken söz konusu olduğunda, üzerine yazılır (Değişkene yeni değer verilmesi. İşleve yeni tanım verilmesi Geçersiz kıl).Just don't declare the variable but initialize (change) in the constructor or static block.

Üst sınıf bloklarında kullanıldığında değer yansıtılır

değişken statik ise statik blok ile başlatma sırasında değeri değiştirin,

class Son extends Dad {
    static { 
       me = 'son'; 
    }
}

veya kurucudaki değişiklik.

Değeri daha sonra herhangi bir blokta da değiştirebilirsiniz. Süper sınıfa yansıyacak


10
Yanıtın daha iyi okunabilirlik için bazı kodları olması gerektiğini düşünüyorum. Sadece Oğul uygulamasını olarak değiştirin class Son extends Dad { static { me = 'son' } }
Cléssio Mendes

97

Kısacası, hayır, bir sınıf değişkenini geçersiz kılmanın bir yolu yoktur.

Gizlediğiniz Java'da sınıf değişkenlerini geçersiz kılmazsınız. Geçersiz kılma, örneğin yöntemlerdir. Gizleme geçersiz kılmadan farklıdır.

Verdiğiniz örnekte, Son sınıfında 'ben' adıyla sınıf değişkenini bildirerek, üst sınıf Baba'dan miras alacağı sınıf değişkenini 'ben' adıyla gizlersiniz. Bir değişkeni bu şekilde gizlemek, üst sınıf Baba'daki 'ben' sınıf değişkeninin değerini etkilemez.

Sorunuzun ikinci kısmı için, nasıl "oğul" yazdırmak için, ben yapıcı aracılığıyla değeri ayarlamak istiyorum. Aşağıdaki kod orijinal sorunuzdan çok fazla olsa da, ben böyle bir şey yazmak istiyorum;

public class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public void printName() {
        System.out.println(name);
    }
}

JLS, bölüm 8.3 - Alan Beyannameleri'nde gizleme hakkında çok daha fazla ayrıntı vermektedir.


1
Geçersiz kılma türetilmiş sınıfta statik bir bloğa sahip olmakla mümkündür
siddagrl

1
@siddagrl: ayrıntılandırabilir misin?
Mr_and_Mrs_D

PersonBu örnekte OP sınıflarından hangisinin yerini alması gerekiyor?
n611x007

1
@naxa Sonve Dadmiras almak gerekir Person, daha sonra super("Son or Dad");onların inşaatçılar çağırmak .
Panzercrisis

Java gibi değişkenleri gizlemek iyi mi kötü mü?
Panzercrisis

31

Evet, printMe()yöntemi geçersiz kıl :

class Son extends Dad {
        public static final String me = "son";

        @Override
        public void printMe() {
                System.out.println(me);
        }
}

Kullandığınız kitaplığın printMe()yöntemi yoksa veya bu yöntemi bile varsa statik bir yöntemdir?
Venkat Sudheer Reddy Aedama

1
Bunu daha gerçek bir örnek yapmak için, "printMe" yönteminin tekrarlamak istemediğiniz mantıkla çok karmaşık bir işlev olabileceğini düşünebilirsiniz. Bu örnekte, onu yazdıran mantığı değil, yalnızca kişinin adını değiştirmek istiyorsunuz. "Son" döndürmek için geçersiz kılacağınız "getName" adlı bir yöntem oluşturmalısınız ve printMe yöntemi, getName yöntemini yazdırmanın bir parçası olarak çağırır.
Halka

17

Bir alıcı oluşturabilir ve ardından bu alıcıyı geçersiz kılabilirsiniz. Özellikle geçersiz kıldığınız değişken kendi başına bir alt sınıfsa yararlıdır. Süper sınıfınızın bir Objectüyesi olduğunu düşünün, ancak alt sınıfınızda bu artık bir olarak tanımlanmıştır Integer.

class Dad
{
        private static final String me = "dad";

        protected String getMe() {
            return me;
        }

        public void printMe()
        {
                System.out.println(getMe());
        }
}

class Son extends Dad
{
        private static final String me = "son";

        @Override
        protected String getMe() {
            return me;
        }
}

public void doIt()
{
        new Son().printMe(); //Prints "son"
}

11

Bunu geçersiz kılacaksanız, bu durumu sabit tutmak için geçerli bir neden görmüyorum. Soyutlama kullanımını öneririm (bkz. Örnek kod). :

     public interface Person {
        public abstract String getName();
       //this will be different for each person, so no need to make it concrete
        public abstract void setName(String name);
    }

Şimdi Baba'yı ekleyebiliriz:

public class Dad implements Person {

    private String name;

    public Dad(String name) {
        setName(name);
    }

    @Override
    public final String getName() {
    return name;
    }

    @Override
    public final void setName(String name) {
        this.name = name;
    }
}

oğul:

public class Son implements Person {

    private String name;

    public Son(String name) {
        setName(name);
    }

    @Override
    public final String getName() {
        return name;
    }

    @Override
    public final void setName(String name) {
        this.name = name;
    }
}

ve baba iyi bir bayanla tanıştı:

public class StepMom implements Person {

    private String name;

    public StepMom(String name) {
        setName(name);
    }

    @Override
    public final String getName() {
        return name;
    }

    @Override
    public final void setName(String name) {
        this.name = name;
    }
}

Bir ailemiz var gibi görünüyor, dünyaya isimlerini söyleyelim:

public class ConsoleGUI {

    public static void main(String[] args) {
        List<Person> family = new ArrayList<Person>();
        family.add(new Son("Tommy"));
        family.add(new StepMom("Nancy"));
        family.add(new Dad("Dad"));
        for (Person person : family) {
            //using the getName vs printName lets the caller, in this case the
            //ConsoleGUI determine versus being forced to output through the console. 
            System.out.print(person.getName() + " ");
            System.err.print(person.getName() + " ");
            JOptionPane.showMessageDialog(null, person.getName());
    }
}

}

System.out Çıktı: Tommy Nancy Dad
System.err yukarıdakiyle aynı (sadece kırmızı yazı tipi var)
JOption Çıktı:
Tommy sonra
Nancy sonra
Dad


1
OP, statüye erişimi değiştirmekle ilgiliydi. Bu nedenle "ben" genel bir "baba" ya da "oğul" idi - her baba ya da oğul için yaratmaya ihtiyaç duymayan bir şeydi ve dolayısıyla statiktir.
RichieHH

Evet, haklısın, statik olduğunu görmedim. Haha, bu benim cevabımı yaklaşık 100 daha az kod satırına çevirecekti, eğer cevaplanırsa.
Head

6

Bu bir tasarım hatası gibi görünüyor.

Statik anahtar kelimeyi kaldırın ve değişkeni örneğin yapıcıda ayarlayın. Bu şekilde Son, değişkeni yapıcısında farklı bir değere ayarlar.


1
bunun nesi yanlış? 'Ben' üye değişkeninin tasarımınızda geçersiz kılınması gerekiyorsa, patrick's doğru çözümdür
Chii

Aslında, her bir değer için değerim aynıysa, sadece 'statik'i kaldırmak iyi olur. Başlatma işleminin yapıcıda olması gerekmez.
Nate Parsons

Doğru, teknik olarak da (bayt kodda) sanırım neredeyse aynı ;-)
Patrick Cornelissen

4

Sınıf değişkenlerinin yalnızca alt sınıflarda gizlenebileceği ve geçersiz kılınamayacağı doğru olsa da, alt sınıflarda geçersiz kılmadan istediğinizi yapmak hala mümkündür printMe ()ve yansıma arkadaşınızdır. Aşağıdaki kodda, açıklık sağlamak için istisna işlemeyi atladım. İlan O notu Lütfen meolarak protectedo alt sınıflarda gizli olacak şekilde, bu bağlamda çok mantıklı olması gibi görünmüyor ...

class Dad
  {
    static String me = "dad";

    public void printMe ()
      {
        java.lang.reflect.Field field = this.getClass ().getDeclaredField ("me");
        System.out.println (field.get (null));
      }
  }

Very interesting, Java.lang.reflect huh? ... +1
nckbrz

3
class Dad
{
    protected static String me = "dad";

    public void printMe()
    {
        System.out.println(me);
    }
}

class Son extends Dad
{
    protected static String _me = me = "son";
}

public void doIt()
{
    new Son().printMe();
}

... "oğul" yazdıracak.


bu orijinal soru ile aynı değil mi?
Corley Brigman

Nedenini açıklayabilir misin ? (cevabınızda)
Mr_and_Mrs_D

3

https://docs.oracle.com/javase/tutorial/java/IandI/hidevariables.html

Adı Gizleme Alanları

Yukarıdaki bağlantıdan

Bir sınıf içinde, üst sınıftaki bir alanla aynı ada sahip bir alan, türleri farklı olsa bile üst sınıfın alanını gizler. Alt sınıf içinde, üst sınıftaki alana basit adıyla başvurulamaz. Bunun yerine, alana bir sonraki bölümde kapsanan süper ile erişilmelidir. Genel olarak, kodun okunmasını zorlaştırdığı için alanların gizlenmesini önermiyoruz.


1
Potansiyel bir çözümün bağlantısı her zaman açığız, ancak lütfen bağlantınızın çevresine bağlam ekleyin, böylece diğer kullanıcılarınız bunun ne olduğunu ve neden orada olduğunu bilmeleri gerekir. Hedef siteye erişilemiyorsa veya kalıcı olarak çevrimdışı olursa, her zaman önemli bir bağlantının en alakalı kısmını belirtin. Harici bir siteye bağlantıdan çok daha fazla olmanın Neden ve nasıl bazı cevapların silinmesinin olası bir nedeni olduğunu dikkate alın. .
FelixSFD

2

yalnızca geçersiz kılma ile printMe():

class Son extends Dad 
{
    public void printMe() 
    {
        System.out.println("son");
    }
}

yapılan atıf meiçinde Dad.printMestatik alana yöntemle örtülü noktalarından Dad.meböylece tek yönlü veya başka ne değiştirirken printMeyapar Son...


2

Bir sınıftaki değişkenleri geçersiz kılamazsınız. Yalnızca yöntemleri geçersiz kılabilirsiniz. Değişkenleri gizli tutmalısınız, aksi takdirde çok fazla sorun yaşayabilirsiniz.


Statiği geçersiz kılamazsınız.
Tom Hawtin - tackline

(ya da en azından mantıklı değil, IFSWIM.)
Tom Hawtin - tackline

Doğru, statik değerleri geçersiz kılamazsınız. Onları GÖSTEREBİLİRSİN veya bana MASKELEME diyen bazı insanlar.
Dale

2

Alan 'geçersiz kılınmış değil gizli olduğu için gerçekten de' baba 'yazar. 'Oğul' yazdıracak üç yaklaşım vardır:

Yaklaşım 1: PrintMe'yi geçersiz kıl

class Dad
{
    protected static String me = "dad";

    public void printMe()
    {
        System.out.println(me);
    }
}

class Son extends Dad
{
    protected static String me = "son";

    @override
    public void printMe()
    {
        System.out.println(me);
    }
}

public void doIt()
{
    new Son().printMe();
}

Yaklaşım 2: Alanı gizleme ve yapıcıda başlatma

class Dad
{
    protected static String me = "dad";

    public void printMe()
    {
        System.out.println(me);
    }
}

class Son extends Dad
{
    public Son()
    {
        me = "son";
    }
}

public void doIt()
{
    new Son().printMe();
}

Yaklaşım 3: Yapıcıdaki bir alanı başlatmak için statik değeri kullanın

class Dad
{
    private static String meInit = "Dad";

    protected String me;

    public Dad() 
    {
       me = meInit;
    }

    public void printMe()
    {
        System.out.println(me);
    }
}

class Son extends Dad
{
    private static String meInit = "son";

    public Son()
    {
        me = meInit;
    }

}

public void doIt()
{
    new Son().printMe();
}

2

Değişkenler taşma işleminde yer almaz. Sadece yöntemler işe yarar. Bir yöntem çağrısı çalışma zamanında çözülür, yani bir yöntem çağırma kararı çalışma zamanında alınır, ancak değişkenler yalnızca derleme zamanında kararlaştırılır. Bu nedenle, başvurusu çalışma zamanı nesnesinin değil çağrılması için kullanılan bu değişken çağrılır.

Aşağıdaki snippet'e bir göz atın:

package com.demo;

class Bike {
  int max_speed = 90;
  public void disp_speed() {
    System.out.println("Inside bike");
 }
}

public class Honda_bikes extends Bike {
  int max_speed = 150;
  public void disp_speed() {
    System.out.println("Inside Honda");
}

public static void main(String[] args) {
    Honda_bikes obj1 = new Honda_bikes();
    Bike obj2 = new Honda_bikes();
    Bike obj3 = new Bike();

    obj1.disp_speed();
    obj2.disp_speed();
    obj3.disp_speed();

    System.out.println("Max_Speed = " + obj1.max_speed);
    System.out.println("Max_Speed = " + obj2.max_speed);
    System.out.println("Max_Speed = " + obj3.max_speed);
  }

}

Kodu çalıştırdığınızda konsol şunları gösterir:

Inside Honda
Inside Honda
Inside bike

Max_Speed = 150
Max_Speed = 90
Max_Speed = 90

0

Tabii ki özel öznitelikler ve alıcılar ve ayarlayıcılar kullanarak yapılması önerilir, ancak aşağıdakileri test ettim ve işe yarıyor ... Koddaki açıklamaya bakın

class Dad
{
    protected static String me = "dad";

    public void printMe()
    {
        System.out.println(me);
    }
}

class Son extends Dad
{
    protected static String me = "son";

    /* 
    Adding Method printMe() to this class, outputs son 
    even though Attribute me from class Dad can apparently not be overridden
    */

    public void printMe()
    {
        System.out.println(me);
    }
}

class Tester
{
    public static void main(String[] arg)
    {
        new Son().printMe();
    }
}

Sooo ... miras kurallarını yeniden tanımladım mı yoksa Oracle'ı zor bir duruma mı soktum? Bana kalırsa, korumalı statik String me bu programı çalıştırdığınızda görebileceğiniz gibi açıkça geçersiz kılınır. Ayrıca, özelliklerin neden geçersiz kılınmaması gerektiği bana bir anlam ifade etmiyor.


1
Bu durumda, değişkeni süper sınıftan "gizlersiniz". Bu geçersiz kılmadan farklıdır ve kalıtımla ilgisi yoktur. Diğer sınıflar, taban sınıfa mı yoksa alt sınıfa mı başvurduğuna ve gördüklerine göre derleme zamanında sabitlenmesine bağlı olarak bir değişkeni veya diğerini görecektir. Alt sınıftaki "ben" adını başka bir adla değiştirirseniz aynı etkiyi elde edersiniz. Çoğu IDE ve kod doğrulama aracı (findbugs vb.), Genellikle yapmak istediğiniz şey olmadığı için bu gibi değişkenleri gizlediğinizde sizi uyaracaktır.
AutomatedMike

Programlamaya sadece kodlama açısından bakıyorsunuz. Hangi iyidir, ancak bu durumda istediğiniz kodlayın. Kodlamaya bir ekip üyesinin bakış açısıyla bakarsanız, alanların neden geçersiz kılınamadığı gibi kurallar netleşir. Sana nedenini söyleyebilirim, ancak bunu bir ekip üyesinin bakış açısından görmüyorsanız, puanlarımı geçersiz olarak göreceksiniz ve bana geçersiz argümanlar atacaksınız.
nckbrz

0

Değişkenleri alt sınıflarda kolayca yeniden atayabildiğinizde neden geçersiz kılmak istiyorsunuz?

Dil tasarımında çalışmak için bu modeli takip ediyorum. Birden çok türetilmiş uygulamada farklı tatlarda kullanılması gereken çerçevenizde ağır bir hizmet sınıfına sahip olduğunuz bir durum olduğunu varsayalım. Bu durumda, süper sınıf mantığını yapılandırmanın en iyi yolu 'tanımlayıcı' değişkenlerini yeniden atamaktır.

public interface ExtensibleService{
void init();
}

public class WeightyLogicService implements ExtensibleService{
    private String directoryPath="c:\hello";

    public void doLogic(){
         //never forget to call init() before invocation or build safeguards
         init();
       //some logic goes here
   }

   public void init(){}    

}

public class WeightyLogicService_myAdaptation extends WeightyLogicService {
   @Override
   public void init(){
    directoryPath="c:\my_hello";
   }

}

0

Hayır. Sınıf değişkenleri çağıran nesne türüne göre çağrıldığından, sınıf değişkenleri (örnek değişkenler için de geçerlidir) Java'da geçersiz kılma özelliği göstermez. Daha açık hale getirmek için hiyerarşiye bir sınıf daha (İnsan) eklendi. Şimdi elimizde

Oğul uzatır Baba İnsan uzatır

Aşağıdaki kodda, bir dizi İnsan, Baba ve Oğul nesnesi üzerinde yineleme yapmaya çalışıyoruz, ancak çağıran nesnenin türü İnsan olarak her durumda İnsan Sınıfının değerlerini yazdırıyor.

    class Human
{
    static String me = "human";

    public void printMe()
    {
        System.out.println(me);
    }
}
class Dad extends Human
{
    static String me = "dad";

}

class Son extends Dad
{
    static String me = "son";
}


public class ClassVariables {
    public static void main(String[] abc)   {
        Human[] humans = new Human[3];
        humans[0] = new Human();
        humans[1] = new Dad();
        humans[2] = new Son();
        for(Human human: humans)   {
            System.out.println(human.me);        // prints human for all objects
        }
    }
}

Yazdırılacak

  • insan
  • insan
  • insan

Sınıf değişkenlerinin geçersiz kılınması gerekmez.

Üst nesnenin referans değişkeninden gerçek nesnenin sınıf değişkenine erişmek istiyorsak, üst referansı (Human object) türüne dökerek bunu derleyiciye açıkça söylememiz gerekir.

    System.out.println(((Dad)humans[1]).me);        // prints dad

    System.out.println(((Son)humans[2]).me);        // prints son

Yazdırılacak

  • baba
  • oğul

Bu sorunun nasıl bir parçası olarak: - Daha önce de önerildiği gibi Son sınıfında printMe () yöntemini geçersiz kılınız, daha sonra

Son().printMe();

Babamın Sınıf değişkeni "ben" gizlenecektir, çünkü "ben" in (Son sınıfında) en yakın bildirimi (Son sınıf printme () yönteminden) öncelik kazanacaktır.


0

Sadece alt sınıf yapıcısında super.variable çağırın

public abstract class Beverage {

int cost;


int getCost() {

    return cost;

}

}`

public class Coffee extends Beverage {


int cost = 10;
Coffee(){
    super.cost = cost;
}


}`

public class Driver {

public static void main(String[] args) {

    Beverage coffee = new Coffee();

    System.out.println(coffee.getCost());

}

}

Çıktı 10'dur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.