কেন সুপার.সুপার.মোথড (); জাভায় অনুমতি নেই?


360

আমি এই প্রশ্নটি পড়েছি এবং ভেবেছিলাম যে সহজেই সমাধান করা হবে (এটি ছাড়া সমাধানযোগ্য নয়) যদি কেউ লিখতে পারেন:

@Override
public String toString() {
    return super.super.toString();
}

এটি অনেক ক্ষেত্রে কার্যকর কিনা তা আমি নিশ্চিত নই, তবে আমি অবাক হয়েছি কেন এটি হয় না এবং যদি অন্য ভাষায় এর মতো কিছু থাকে।

তোমরা কি ভাবো?

সম্পাদনা: স্পষ্ট করার জন্য: হ্যাঁ আমি জানি, জাভাতে এটি অসম্ভব এবং আমি সত্যিই এটি মিস করি না। এটি এমন কিছু নয় যা আমি প্রত্যাশা করেছিলাম এবং একটি সংকলক ত্রুটি পেয়ে অবাক হয়েছিল। আমার কেবল ধারণা ছিল এবং এটি আলোচনা করতে পছন্দ করি।


7
কল অনুপস্থিত super.super.toString()আপনার নিজের সিদ্ধান্ত contradicts যখন আপনি একটি বর্গ এইভাবে গ্রহণ প্রসারিত করতে পছন্দ করে সব (না কিছু) তার বৈশিষ্ট্য।
দয়ামুন

উত্তর:


484

এটি এনক্যাপসুলেশন লঙ্ঘন করে। অভিভাবক শ্রেণীর আচরণকে আপনি বাইপাস করতে সক্ষম হবেন না। কখনও কখনও আপনার নিজের শ্রেণীর আচরণকে (বিশেষত একই পদ্ধতির মধ্যে থেকে) বাইপাস করতে সক্ষম হওয়া আপনার বোধগম্য হয় তবে আপনার পিতামাতার নয়। উদাহরণস্বরূপ, ধরুন আমাদের একটি "আইটেমের সংগ্রহ" আছে, "লাল আইটেমের সংকলন" উপস্থাপনকারী একটি সাবক্লাস এবং "বড় বড় আইটেমগুলির সংকলন" উপস্থাপনকারী একটি উপশ্রেন রয়েছে। এটি বোধগম্য হয়:

public class Items
{
    public void add(Item item) { ... }
}

public class RedItems extends Items
{
    @Override
    public void add(Item item)
    {
        if (!item.isRed())
        {
            throw new NotRedItemException();
        }
        super.add(item);
    }
}

public class BigRedItems extends RedItems
{
    @Override
    public void add(Item item)
    {
        if (!item.isBig())
        {
            throw new NotBigItemException();
        }
        super.add(item);
    }
}

এটি দুর্দান্ত - রেড আইটেমগুলি সর্বদা আত্মবিশ্বাসী হতে পারে যে এতে থাকা আইটেমগুলি সমস্ত লাল। এখন অনুমান করা আমরা ছিলেন super.super.add () কল করতে পারবেন:

public class NaughtyItems extends RedItems
{
    @Override
    public void add(Item item)
    {
        // I don't care if it's red or not. Take that, RedItems!
        super.super.add(item);
    }
}

এখন আমরা যা খুশি তা যোগ করতে পারতাম এবং আক্রমণকারীটি RedItemsভেঙে গেছে।

যে জানার জন্য?


38
সুন্দর উদাহরণ। তবে আমি ভেবেছিলাম যখন বেস ক্লাসটি আইটেম গ্রহণ করে তখন এটি খারাপ নকশা, তবে উত্পন্ন শ্রেণি সেগুলি প্রত্যাখ্যান করে, কারণ প্রাপ্ত বর্গটি বেস-শ্রেণীর (বিকল্প প্রতিবেদনের নীতি লঙ্ঘন) জন্য ড্রপ-ইন প্রতিস্থাপন হিসাবে ব্যবহার করা যায় না। এটা কি সঠিক চিন্তাভাবনা, নাকি এরকম শ্রেণিবিন্যাস পরিষ্কার?
জোহানেস স্কাউব -

5
আপনি কি উত্তরাধিকারের চেয়ে বেশি রচনা বোঝাতে চান? এই উদাহরণটি উত্তরাধিকার এড়ানোর কোনও কারণ নয় - যদিও প্রচুর অন্য রয়েছে।
জন স্কিটি

3
@ টিম: এটি কেবল এনক্যাপসুলেশন লঙ্ঘনের একটি সহজ-বোঝার উদাহরণ। এটি পরিবর্তে একটি সম্পত্তি সেট করা যেতে পারে। এছাড়াও, সমস্ত দিক কোনও ধরণের স্তরে দৃশ্যমান হবে না। জেনেরিক্স সবকিছুর উত্তর নয়।
জন স্কিটি

12
@ জোহানেস শ্যাব-লিটব আমি মনে করি যে এটি লিসকোভ প্রতিস্থাপনের নীতি লঙ্ঘন করে, যেহেতু আইটেমের চুক্তিতে একটি কোড কোড করে এবং রেড আইটেমগুলির উদাহরণ ব্যবহার করে, একজন অপ্রত্যাশিত নটরেডআইটেম এক্সসেপশন পাবে। আমাকে সর্বদা শেখানো হয়েছিল যে উপ-শ্রেণীর একটি দুর্দান্ত সেট ইনপুট নেওয়া উচিত এবং আউটপুটটির একটি উপসেট ফেরত দেওয়া উচিত। অন্য কথায়, একটি উপ শ্রেণীর কখনই এমন কোনও ইনপুট প্রত্যাখ্যান করা উচিত নয় যা সুপার ক্লাসের জন্য বৈধ বা আউটপুট উত্পাদন করতে পারে যা সুপার বর্গ উত্পাদন করতে পারে না, এর মধ্যে এমন একটি ত্রুটি রয়েছে যা সুপার বর্গ নিক্ষেপ করে না।
কনস্ট্যান্টিন তারাশচানস্কি

4
@ পাইচাকারার: ​​কখনও কখনও বই, কখনও কখনও ব্লগ পোস্ট, কখনও কখনও কেবল অভিজ্ঞতা ...
জন স্কিটি 4'16

72

আমি মনে করি জন স্কিটির সঠিক উত্তর আছে। আমি কেবল যুক্ত করতে চাই আপনি কাস্টিং দ্বারা সুপারক্লাসের সুপারক্লাস থেকে ছায়াময় ভেরিয়েবল অ্যাক্সেস করতে পারেনthis :

interface I { int x = 0; }
class T1 implements I { int x = 1; }
class T2 extends T1 { int x = 2; }
class T3 extends T2 {
        int x = 3;
        void test() {
                System.out.println("x=\t\t"          + x);
                System.out.println("super.x=\t\t"    + super.x);
                System.out.println("((T2)this).x=\t" + ((T2)this).x);
                System.out.println("((T1)this).x=\t" + ((T1)this).x);
                System.out.println("((I)this).x=\t"  + ((I)this).x);
        }
}

class Test {
        public static void main(String[] args) {
                new T3().test();
        }
}

যা আউটপুট উত্পাদন করে:

x = 3
সুপার.এক্স = 2
((টি 2) এটি) .x = 2
((টি 1) এটি) .x = 1
((আমি) এটি) .x = 0

( জেএলএস থেকে উদাহরণ )

তবে এটি মেথড কলগুলির জন্য কাজ করে না কারণ মেথড কলগুলি বস্তুর রানটাইম ধরণের ভিত্তিতে নির্ধারিত হয়।


6
যদি আপনার সুপারক্লাসের মতো একটি ভেরিয়েবল একই নামে থাকে এবং কোনও কারণে আপনি এটি পরিবর্তন করতে পারবেন না (বা তার অনুমতি নেই) তবে আপনি এখনও একই নামের সাথে সুপারক্লাসের ভেরিয়েবলটি অ্যাক্সেস করতে পারেন। তুমি কি জিজ্ঞাসা করছ? আচ্ছা ... আমি এটি কখনও ব্যবহার করি নি।
মাইকেল মায়ার্স

এক্সপ্রেশন ডকুমেন্টের দুর্দান্ত লিঙ্ক। ওসিপিজেপির জন্য অধ্যয়নরত লোকদের জন্য কয়েকটি দুর্দান্ত উদাহরণ।
গর্ডন

অসাধারণ. আমি কখনও castালাই ব্যবহার করার কথা ভাবিনি।
থমাস এডিং

ক্লাস টি 1 কীভাবে ওভাররাইড ভেরিয়েবল x এ আসে? তার স্থির ফাইনাল ডিফল্ট অধিকার?
অমরনাথ হরিশ

@ অমরনাথারিশ: এটি ওভাররাইড করা হয়নি, এবং ক্ষেত্রগুলি ডিফল্টরূপে প্যাকেজ-সুরক্ষিত অ চূড়ান্ত।
মাইকেল মায়ার্স

41

আমি মনে করি নিম্নলিখিত কোডগুলি বেশিরভাগ ক্ষেত্রে সুপার.সুপার ... সুপার.মোথড () ব্যবহার করার অনুমতি দেয়। (এটি করা কুৎসিত হলেও)

সংক্ষেপে

  1. পূর্বপুরুষের ধরণের অস্থায়ী উদাহরণ তৈরি করুন
  2. আসল বস্তু থেকে অস্থায়ী থেকে ক্ষেত্রের মানগুলি অনুলিপি করুন
  3. অস্থায়ী বস্তুর উপর লক্ষ্য পদ্ধতি প্রার্থনা করুন
  4. পরিবর্তিত মানগুলি মূল অবজেক্টে ফিরে অনুলিপি করুন

ব্যবহার:

public class A {
   public void doThat() { ... }
}

public class B extends A {
   public void doThat() { /* don't call super.doThat() */ }
}

public class C extends B {
   public void doThat() {
      Magic.exec(A.class, this, "doThat");
   }
}


public class Magic {
    public static <Type, ChieldType extends Type> void exec(Class<Type> oneSuperType, ChieldType instance,
            String methodOfParentToExec) {
        try {
            Type type = oneSuperType.newInstance();
            shareVars(oneSuperType, instance, type);
            oneSuperType.getMethod(methodOfParentToExec).invoke(type);
            shareVars(oneSuperType, type, instance);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    private static <Type, SourceType extends Type, TargetType extends Type> void shareVars(Class<Type> clazz,
            SourceType source, TargetType target) throws IllegalArgumentException, IllegalAccessException {
        Class<?> loop = clazz;
        do {
            for (Field f : loop.getDeclaredFields()) {
                if (!f.isAccessible()) {
                    f.setAccessible(true);
                }
                f.set(target, f.get(source));
            }
            loop = loop.getSuperclass();
        } while (loop != Object.class);
    }
}

10
প্রতিবিম্বের সাহায্যে আপনি যে কোনও কিছু করতে পারেন, হ্যাঁ :) আপনি এমনকি স্ট্রিংগুলিকে পরিবর্তনযোগ্যও করতে পারেন।
বালুসসি

23
কী ভয়াবহ কাজ! একেবারে কীভাবে করা যায় তা নির্ধারণের জন্য আমি আপনাকে +1 দিচ্ছি :)
ল্যারি ওয়াতানাবে

6
এটি একটি দুর্দান্ত কৌশল কিন্তু এটি সর্বদা অযাচিত, এখনও প্রয়োজনীয়) সুপার.সুপারকে কল করার সমতুল্য নয় এবং এটি হ'ল কারণ সুপার.সুপার কলটি সি (সি + বি + এ) এর প্রসঙ্গ বহন করবে যেখানে আপনার উত্তরগুলি উদাহরণ তৈরি করে বি এবং সি এর প্রসঙ্গ ব্যতীত এ এর ​​সুতরাং উদাহরণস্বরূপ, getContext () নামক প্রতিটি doThat যদি এই উত্তরটি কার্যকর হয় না, এবং getContext প্রতিটি শ্রেণিতে আলাদাভাবে প্রয়োগ করা হয়েছিল। আপনার উত্তরে এটি A এর getContext () ব্যবহার করবে যখন অপ্রাপ্য সুপারকে ডাকা হবে up
inor

হুম। কিছু ক্ষেত্রে, সম্ভবত আপনি গতিশীল প্রক্সি ( javahowto.blogspot.co.uk/2011/12/… ) দিয়ে ইনরের আপত্তি কাটিয়ে উঠতে পারেন, মূল অবজেক্টে পুনর্নির্দেশ পদ্ধতি পদ্ধতি (প্রতিটি কলের পরে ভেরিয়েবল সিঙ্ক্রোনাইজিং)? মনে হচ্ছে প্রক্সিগুলির একটি ইন্টারফেস বাস্তবায়ন করার জন্য সমস্ত কিছু প্রয়োজন। এছাড়াও, আমি আশ্চর্য হয়েছি যে সুপার-ক্লাসের পক্ষে এটির একটি সুপার-সুপার পদ্ধতিগুলির মধ্যে একটি বিশেষভাবে কল করা সম্ভব হয়েছিল এবং আপনার সেগুলি পুনঃনির্দেশ করার দরকার নেই ....
এরহানিস

আমি অন্য একটি মন্তব্যে বলেছি যে ব্লক করা super.super.প্রোগ্রামারগুলিকে একটি কাজের ভিত্তিতে অনুসরণ করার জন্য নিজেকে পায়ে গুলি করার নতুন, সংশ্লেষিত এবং গুরুতর উপায়গুলি সন্ধানের জন্য আমন্ত্রণ জানায়, এটি এর একটি নিখুঁত উদাহরণ, কারণ আপনার সহকর্মীরা সম্ভবত কিছু লেখার জন্য আপনাকে এতটা ঘৃণা করবে এটি পছন্দ করুন যে তারা ব্যক্তিগতভাবে এবং আক্ষরিকভাবে আপনাকে পায়ে গুলি করবে shoot +1
ব্র্যাডেন সেরা

11

আমার মন্তব্য করার মতো যথেষ্ট খ্যাতি নেই তাই আমি এটি অন্যান্য উত্তরগুলিতে যুক্ত করব।

জন স্কিটি একটি সুন্দর উদাহরণ সহ দুর্দান্তভাবে উত্তর দেয়। ম্যাট বি এর একটি বক্তব্য রয়েছে: সমস্ত সুপারক্লাসে সুপার থাকে না। আপনি যদি কোনও সুপারের সুপারকে কল করেন তবে আপনার কোডটি ভঙ্গ হবে।

অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং (যা জাভা) সমস্ত কিছুই ফাংশন নয়। আপনি যদি টাস্ক ওরিয়েন্টেড প্রোগ্রামিং চান তবে সি ++ বা অন্য কিছু বেছে নিন। যদি আপনার অবজেক্টটি এটি সুপার ক্লাসে ফিট করে না, তবে আপনাকে এটি "পিতামহক শ্রেণীর" সাথে যুক্ত করতে হবে, একটি নতুন ক্লাস তৈরি করতে হবে, বা এটির সাথে মানানসই আরও একটি সুপার সন্ধান করতে হবে।

ব্যক্তিগতভাবে, আমি এই সীমাবদ্ধতাটিকে জাভার অন্যতম বৃহৎ শক্তি বলে মনে করেছি। আমি ব্যবহৃত অন্যান্য ভাষার তুলনায় কোডটি কিছুটা অনমনীয়, তবে আমি কী আশা করি তা সবসময় জানি। এটি জাভাটির "সহজ এবং পরিচিত" লক্ষ্যটিতে সহায়তা করে। আমার মনে, সুপার.সুপারকে কল করা সহজ বা পরিচিত নয়। সম্ভবত বিকাশকারীরাও কি একই অনুভব করেছেন?


3
আপনি বলেছেন "সমস্ত সুপারক্লাসে সুপার থাকে না"। ঠিক আছে, জাভা.এলং ছাড়া আর কিছুই নয় b অবজেক্টটি আপনাকে "নাল" দিতে পারে। তাই আমি বলব, প্রায় সকলেরই সুপার আছে।
টিম বাথ 18

অ্যাপ্লিকেশন প্রোগ্রামার লেখার প্রতিটি শ্রেণীর একটি "সুপার" থাকে (জাভা.এলং.অবজেক্ট না, তবে অ্যাপ্লিকেশন প্রোগ্রামার এটি লেখেন না))
ফাইনেল

2
সুপার.সুপার.সুপার তৈরি করে খুব সহজে সমাধান করা হয়েছে ... অনেক বেশি সুপার থাকলে কমপাইল টাইপ ত্রুটি হয়। জাভা বিবেচনায় কেবল জনসাধারণের উত্তরাধিকার রয়েছে, যদি কেউ উত্তরাধিকারের শ্রেণিবিন্যাস পরিবর্তন করে তবে আপনি ইন্টারফেসটি পরিবর্তন করছেন। সুতরাং আমি উদ্বিগ্ন হব না যে সুপার ^ n ভয়ঙ্কর।
টমাস এডিং

7

এটি করার কয়েকটি ভাল কারণ রয়েছে। আপনার কাছে একটি সাবক্লাস থাকতে পারে যার একটি পদ্ধতি রয়েছে যা ভুলভাবে প্রয়োগ করা হয়েছে, তবে পিতামাতার পদ্ধতিটি সঠিকভাবে প্রয়োগ করা হয়েছে। এটি একটি তৃতীয় পক্ষের লাইব্রেরির অন্তর্ভুক্ত বলে আপনি উত্সটি পরিবর্তন করতে অক্ষম / অনিচ্ছুক হতে পারেন। এই ক্ষেত্রে, আপনি একটি সাবক্লাস তৈরি করতে চান তবে সুপার.সুপার পদ্ধতিটি কল করতে একটি পদ্ধতি ওভাররাইড করতে পারেন।

অন্য কিছু পোস্টার হিসাবে দেখানো হয়েছে, প্রতিবিম্বের মাধ্যমে এটি করা সম্ভব, তবে এর মতো কিছু করাও উচিত

(সুপারসপার ক্লাস এটি) .মাথোদ ();

আমি এই মুহুর্তে এই সমস্যাটির সাথে মোকাবিলা করছি - দ্রুত সমাধানটি হ'ল সাবক্লাস পদ্ধতিতে সুপারক্লাস পদ্ধতিটি অনুলিপি করে আটকানো হবে :)


1
কোনও পদ্ধতিতে কল করার আগে কাস্ট করা সেই পদ্ধতিতে পরিবর্তন হয় না যা ated এটি সর্বদা সাবক্লাসের প্রয়োগ হয় যা ব্যবহার করা হয়, কখনও সুপারের নয়। দেখুন, উদাহরণস্বরূপ, স্ট্যাকওভারফ্লো.com
জোশুয়া গোল্ডবার্গ

1
@ ল্যারিটি হ'ল আমি যে পরিস্থিতিতে ছিলাম ঠিক তা-ই এবং আমি ঠিক ঠিক ব্যবহার করেছি। ভাল কল!
বিসিআর

আপনার যদি প্রয়োজনীয় পদ্ধতির কোড থাকে তবে আপনি সমস্ত প্রয়োজনীয় ক্ষেত্রগুলি খুলতে এবং আপনার সাবক্লাসে এই কোডটি চালাতে পারেন।
এনাইবি

6

অন্যরা যে খুব ভাল পয়েন্ট তৈরি করেছে তা ছাড়াও আমার মনে হয় এর আরও একটি কারণ আছে: সুপারক্লাসের সুপারক্লাস না থাকলে কী হয়?

যেহেতু প্রতিটি শ্রেণি স্বাভাবিকভাবেই প্রসারিত হয় (কমপক্ষে) Object, super.whatever()সর্বদা সুপারক্লাসের কোনও পদ্ধতিতে উল্লেখ করবে। কিন্তু যদি আপনার ক্লাসটি কেবল প্রসারিত হয় Object- তবে কী super.superবোঝায়? কীভাবে সেই আচরণটি পরিচালনা করা উচিত - একটি সংকলক ত্রুটি, একটি নলপয়েন্টার, ইত্যাদি?

আমি মনে করি এটির অনুমতি না পাওয়ার প্রাথমিক কারণ হ'ল এটি encapsulation লঙ্ঘন করে তবে এটি একটি ছোট কারণও হতে পারে।


4
স্পষ্টতই, এটি একটি সংকলক ত্রুটি হবে - এবং এটি সংকলকটিতে রয়েছে এমন তথ্য।
মাইকেল বর্গওয়ার্ট

4

আমি মনে করি আপনি যদি কোনও পদ্ধতি ওভাররাইট করে এবং এর সমস্ত সুপার-ক্লাসের সংস্করণ (যেমন বলুন equals) করতে চান তবে আপনি কার্যত সর্বদা ডাইরেক্ট সুপারক্লাস সংস্করণটি প্রথমে কল করতে চান, যদি এটি চায় তবে তার সুপারক্লাস সংস্করণটি কল করবে ।

আমি মনে করি এটি কেবলমাত্র কোনও পদ্ধতির স্বেচ্ছাসেবক সুপারক্লাসের সংস্করণটি কল করার জন্য এটি খুব কমই বোঝা যায় (যদি তা মোটামুটি does তবে এটি ঘটে এমন কোনও ক্ষেত্রে আমি ভাবতে পারি না)। জাভাতে আদৌ সম্ভব কিনা তা আমি জানি না। এটি সি ++ এ করা যেতে পারে:

this->ReallyTheBase::foo();

6
কেউ যদি একটি পদ্ধতি ভুলভাবে প্রয়োগ করে একটি সাবক্লাস লিখে থাকেন তবে সুপারক্লাস পদ্ধতিটি 90% কাজটি করে তা বোঝা যায়। তারপরে আপনি একটি সাবক্লাস তৈরি করতে এবং সুপারক্লাস সুপারক্লাস পদ্ধতিটি কল করার পদ্ধতিটি ওভাররাইড করতে চান এবং আপনার নিজের 10% যুক্ত করতে পারেন।
ল্যারি ওয়াতানাবে

3

অনুমান হিসাবে, কারণ এটি প্রায়শই ব্যবহৃত হয় না। আমি এটি ব্যবহার করতে দেখতে পেলাম কেবল কারণ যদি আপনার প্রত্যক্ষ পিতামাতার কিছু কার্যকারিতা ওভাররাইড হয়ে যায় এবং আপনি এটিকে মূলটিতে ফিরিয়ে আনার চেষ্টা করছেন।

যা আমার কাছে ওও নীতির বিরুদ্ধে বলে মনে হয়, যেহেতু ক্লাসের প্রত্যক্ষ পিতামাতার সাথে আপনার পিতামাতার চেয়ে আপনার ক্লাসের সাথে আরও জড়িত হওয়া উচিত।


3

তাকান এই গিটহাব প্রকল্প, বিশেষ করে objectHandle পরিবর্তনশীল। এই প্রকল্পটি দেখায় যে কীভাবে প্রকৃতপক্ষে এবং নির্ভুলভাবে কোনও নাতি-নাতনিতে দাদা-পিতা পদ্ধতিটি কল করা যায়।

লিঙ্কটি ভাঙার ক্ষেত্রে কেবল কোডটি এখানে রয়েছে:

import lombok.val;
import org.junit.Assert;
import org.junit.Test;

import java.lang.invoke.*;

/*
Your scientists were so preoccupied with whether or not they could, they didn’t stop to think if they should.
Please don't actually do this... :P
*/
public class ImplLookupTest {
    private MethodHandles.Lookup getImplLookup() throws NoSuchFieldException, IllegalAccessException {
        val field = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
        field.setAccessible(true);
        return (MethodHandles.Lookup) field.get(null);
    }

    @Test
    public void test() throws Throwable {
        val lookup = getImplLookup();
        val baseHandle = lookup.findSpecial(Base.class, "toString",
            MethodType.methodType(String.class),
            Sub.class);
        val objectHandle = lookup.findSpecial(Object.class, "toString",
            MethodType.methodType(String.class),
            // Must use Base.class here for this reference to call Object's toString
            Base.class);
        val sub = new Sub();
        Assert.assertEquals("Sub", sub.toString());
        Assert.assertEquals("Base", baseHandle.invoke(sub));
        Assert.assertEquals(toString(sub), objectHandle.invoke(sub));
    }

    private static String toString(Object o) {
        return o.getClass().getName() + "@" + Integer.toHexString(o.hashCode());
    }

    public class Sub extends Base {
        @Override
        public String toString() {
            return "Sub";
        }
    }

    public class Base {
        @Override
        public String toString() {
            return "Base";
        }
    }
}

শুভ কোডিং !!!!


আপনার বিজ্ঞানীরা এগুলি করতে পারেন কিনা তা নিয়ে এতটাই ডুবে ছিলেন, তারা উচিত কিনা তা ভাবেনি। দয়া করে আসলে এটি করবেন না ...: পি 🤔
টিম বাথ

হ্যাঁ, এগুলি কোডারের কথা, আমার নয়। আমার মতে, আমি মনে করি আপনার সম্ভবত
কোনও দিন

2

সম্ভব হলে আমি সুপার.সুপার মেথড বডিটি অন্য পদ্ধতিতে রেখে দিতাম

class SuperSuperClass {
    public String toString() {
        return DescribeMe();
    }

    protected String DescribeMe() {
        return "I am super super";
    }
}

class SuperClass extends SuperSuperClass {
    public String toString() {
        return "I am super";
    }
}

class ChildClass extends SuperClass {
    public String toString() {
        return DescribeMe();
    }
}

বা আপনি যদি সুপার-সুপার ক্লাসটি পরিবর্তন করতে না পারেন তবে আপনি এটি চেষ্টা করে দেখতে পারেন:

class SuperSuperClass {
    public String toString() {
        return "I am super super";
    }
}

class SuperClass extends SuperSuperClass {
    public String toString() {
        return DescribeMe(super.toString());
    }

    protected String DescribeMe(string fromSuper) {
        return "I am super";
    }
}

class ChildClass extends SuperClass {
    protected String DescribeMe(string fromSuper) {
        return fromSuper;
    }
}

উভয় ক্ষেত্রে,

new ChildClass().toString();

"আমি সুপার সুপার" এর ফলাফল


আমি কেবল নিজেকে এমন একটি পরিস্থিতিতে পেয়েছি যেখানে আমি সুপারসুপারক্লাস এবং চাইল্ডক্লাসের মালিক কিন্তু সুপারক্লাস নয়, তাই আমি প্রথম সমাধানটি দরকারী বলে মনে করি।
xofon

1

প্রতিবিম্ব ব্যবহার করে কমপক্ষে সুপারক্লাসের সুপারক্লাসের ক্লাস পাওয়া সম্ভব বলে মনে হচ্ছে, যদিও এটির উদাহরণস্বরূপ প্রয়োজনীয় নয়; যদি এটি কার্যকর হতে পারে তবে দয়া করে জাভাডোকটি http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#getSuperclass () এ বিবেচনা করুন


1
public class A {

     @Override
     public String toString() {
          return "A";
     }

}


public class B extends A {

     @Override
     public String toString() {
          return "B";
     }

}

public class C extends B {

     @Override
     public String toString() {
          return "C";
     }

}


public class D extends C {

     @Override
     public String toString() {
          String result = "";
          try {
                result = this.getClass().getSuperclass().getSuperclass().getSuperclass().newInstance().toString();
          } catch (InstantiationException ex) {
                Logger.getLogger(D.class.getName()).log(Level.SEVERE, null, ex);
          } catch (IllegalAccessException ex) {
                Logger.getLogger(D.class.getName()).log(Level.SEVERE, null, ex);
          }
          return result;
     }

}

public class Main {

     public static void main(String... args) {
          D d = new D();
          System.out.println(d);

     }
}

রান: একটি বিল্ড সাফল্য (মোট সময়: 0 সেকেন্ড)


1
আমি দেখতে পাচ্ছি, তবে আপনি একটি নতুন উদাহরণ তৈরি করছেন যাতে বস্তুর কোনও রাজ্য থাকলে এটি কাজ করবে না।
টিম বাথ

1

যখন আপনি বেস ক্লাসের কোডটি পরিবর্তন করতে পারবেন না তখন সুপার.সুপার.মোথডো () কল করা অর্থযুক্ত। আপনি প্রায়শই বিদ্যমান লাইব্রেরি প্রসারিত করার সময় এটি প্রায়ই ঘটে।

নিজেকে প্রথমে জিজ্ঞাসা করুন, আপনি কেন এই শ্রেণিটি বাড়িয়ে দিচ্ছেন? যদি উত্তরটি হয় "কারণ আমি এটি পরিবর্তন করতে পারি না" তবে আপনি আপনার অ্যাপ্লিকেশনটিতে সঠিক প্যাকেজ এবং শ্রেণি তৈরি করতে পারেন, এবং দুষ্টু পদ্ধতিতে আবার লিখতে পারেন বা প্রতিনিধি তৈরি করতে পারেন:

package com.company.application;

public class OneYouWantExtend extends OneThatContainsDesiredMethod {

    // one way is to rewrite method() to call super.method() only or 
    // to doStuff() and then call super.method()

    public void method() {
        if (isDoStuff()) {
            // do stuff
        }
        super.method();
    }

    protected abstract boolean isDoStuff();


    // second way is to define methodDelegate() that will call hidden super.method()

    public void methodDelegate() {
        super.method();
    }
    ...
}

public class OneThatContainsDesiredMethod {

    public void method() {...}
    ...
}

উদাহরণস্বরূপ, আপনি org.springframework.test.context.junit4.SpringJUnit4ClassRunner ক্লাসটি আপনার অ্যাপ্লিকেশনটিতে তৈরি করতে পারেন যাতে এই বর্গটি জার থেকে আসলটির আগে লোড করা উচিত। তারপরে পুনর্লিখন পদ্ধতি বা কনস্ট্রাক্টর।

মনোযোগ দিন: এটি পরম হ্যাক, এবং এটি ব্যবহারের জন্য অত্যন্ত প্রস্তাবিত নয় তবে এটি কাজ করছে! শ্রেণি লোডারদের সাথে সম্ভাব্য সমস্যার কারণে এই পদ্ধতির ব্যবহার বিপজ্জনক। এছাড়াও প্রতিবার ওভাররাইট করা ক্লাস যুক্ত লাইব্রেরি আপডেট করার সময় এটি সমস্যার কারণ হতে পারে।


1

আমার যখন এ জাতীয় পরিস্থিতি ছিল তখন যখন আর্কিটেকচারটি একটি সাধারণ কাস্টমবেসক্লাসে সাধারণ কার্যকারিতা তৈরি করে যা বিভিন্ন উত্সভুক্ত শ্রেণীর পক্ষে প্রয়োগ করে। তবে, একটি নির্দিষ্ট উত্পন্ন শ্রেণীর জন্য আমাদের নির্দিষ্ট পদ্ধতির জন্য সাধারণ যুক্তি অবলম্বন করতে হবে। এই ধরনের ক্ষেত্রে, আমাদের অবশ্যই একটি সুপার.সুপার.মোথডেক্স বাস্তবায়ন ব্যবহার করা উচিত।

আমরা কাস্টমবেসক্লাসে একটি বুলিয়ান সদস্য প্রবর্তন করে এটি অর্জন করেছি, যা পছন্দসইভাবে কাস্টম বাস্তবায়ন স্থগিত করতে এবং যেখানে আকাঙ্ক্ষিত সেখানে ডিফল্ট কাঠামো বাস্তবায়নের জন্য ব্যবহার করা যেতে পারে।

        ...
        FrameworkBaseClass (....) extends...
        {
           methodA(...){...}
           methodB(...){...}
        ...
           methodX(...)
        ...
           methodN(...){...}

        }
        /* CustomBaseClass overrides default framework functionality for benefit of several derived classes.*/
        CustomBaseClass(...) extends FrameworkBaseClass 
        {
        private boolean skipMethodX=false; 
        /* implement accessors isSkipMethodX() and setSkipMethodX(boolean)*/

           methodA(...){...}
           methodB(...){...}
        ...
           methodN(...){...}

           methodX(...){
                  if (isSkipMethodX()) {
                       setSKipMethodX(false);
                       super.methodX(...);
                       return;
                       }
                   ... //common method logic
            }
        }

        DerivedClass1(...) extends CustomBaseClass
        DerivedClass2(...) extends CustomBaseClass 
        ...
        DerivedClassN(...) extends CustomBaseClass...

        DerivedClassX(...) extends CustomBaseClass...
        {
           methodX(...){
                  super.setSKipMethodX(true);
                  super.methodX(...);
                       }
        }

তবে, কাঠামোগত পাশাপাশি অ্যাপ্লিকেশন অনুসারে ভাল আর্কিটেকচার নীতিগুলি অনুসরণ করে, আমরা ISA পদ্ধতির পরিবর্তে hasA পদ্ধতির ব্যবহারের মাধ্যমে সহজেই এ জাতীয় পরিস্থিতি এড়াতে পারি। তবে সর্বদা এটি জায়গায় ভালভাবে নকশা করা আর্কিটেকচার আশা করা খুব ব্যবহারিক নয়, এবং তাই শক্ত নকশার নীতিগুলি থেকে দূরে সরে আসা এবং এই জাতীয় হ্যাকগুলি প্রবর্তন করা প্রয়োজন। শুধু আমার 2 সেন্ট ...


1

@ জোন স্কিটি সুন্দর ব্যাখ্যা। আইএমও যদি কেউ সুপার.সুপার পদ্ধতিতে কল করতে চায় তবে অবশ্যই একজনকে তাত্ক্ষণিক পিতামাতার আচরণকে উপেক্ষা করতে হবে, তবে গ্র্যান্ড পিতামাতার আচরণটি অ্যাক্সেস করতে হবে। উদাহরণস্বরূপ এটি অর্জন করা যেতে পারে। নীচের কোড হিসাবে

public class A {
    protected void printClass() {
        System.out.println("In A Class");
    }
}

public class B extends A {

    @Override
    protected void printClass() {
        if (!(this instanceof C)) {
            System.out.println("In B Class");
        }
        super.printClass();
    }
}

public class C extends B {
    @Override
    protected void printClass() {
        System.out.println("In C Class");
        super.printClass();
    }
}

এখানে ড্রাইভার ক্লাস,

public class Driver {
    public static void main(String[] args) {
        C c = new C();
        c.printClass();
    }
}

এর আউটপুট হবে

In C Class
In A Class

এই ক্ষেত্রে ক্লাস বি প্রিন্টক্লাস আচরণ উপেক্ষা করা হবে। আমি সুপার.সুপার অর্জনের জন্য এটি একটি আদর্শ বা ভাল অনুশীলন সম্পর্কে নিশ্চিত নই, তবে এটি এখনও কাজ করছে।


1
ঠিক আছে, এটি সৃজনশীল তবে সত্যই আমার প্রশ্নের উত্তর দেয় না। সি এখনও সুপার.সুপারকে কল করে না, বি কেবল অন্যরকম আচরণ করে। আপনি যদি A এবং B পরিবর্তন করতে পারেন তবে উদাহরণ হিসাবে ব্যবহারের পরিবর্তে আপনি কেবল অন্য পদ্ধতি যুক্ত করতে পারেন। আপনার ক্ষেত্রে এ এবং বি অ্যাক্সেস নেই এবং সেগুলি পরিবর্তন করতে পারে না সে ক্ষেত্রে সুপার.সুপার.ফু আপনাকে সাহায্য করবে।
টিম বাথ

@ টিমবুথিতে সম্মত হন, তবে যদি কেউ সুপার.সুপারকে কল করতে চান তবে তিনি / তিনি ইচ্ছাকৃতভাবে পিতাম শ্রেণীর আচরণকে উপেক্ষা করতে চান, সুতরাং জাভা বিদ্যমান বাক্য বাক্য গঠন দ্বারা আপনার কেবল সেই জিনিসটি অর্জন করা প্রয়োজন। (বিকল্পগুলির যে কোনও বিকল্প আপনি চান / ভিন্ন পদ্ধতি)
সঞ্জয় জৈন

0

আপনি যদি ভাবেন যে আপনাকে সুপারক্লাসের দরকার হবে, আপনি এই শ্রেণীর জন্য একটি পরিবর্তনশীল হিসাবে এটি উল্লেখ করতে পারেন। উদাহরণ স্বরূপ:

public class Foo
{
  public int getNumber()
  {
    return 0;
  }
}

public class SuperFoo extends Foo
{
  public static Foo superClass = new Foo();
  public int getNumber()
  {
    return 1;
  }
}

public class UltraFoo extends Foo
{
  public static void main(String[] args)
  {
    System.out.println(new UltraFoo.getNumber());
    System.out.println(new SuperFoo().getNumber());
    System.out.println(new SuperFoo().superClass.getNumber());
  }
  public int getNumber()
  {
    return 2;
  }
}

মুদ্রণ করা উচিত:

2
1
0

2
আপনার এক্সামল এক ধরণের ... ভাল খারাপ, কারণ আপনি স্থির পদ্ধতি ব্যবহার করেন use স্থির পদ্ধতিগুলি ব্যবহার করার সময় আপনার ভেরিয়েবল বা সুপারের মোটেই প্রয়োজন হয় না। হতে পারে আপনি এখানে কিছু বেসিক ওও ধারণা মিস করেছেন, নিশ্চিত হয়ে নিন যে আপনি এটি পড়েছেন। দুঃখিত, দুঃখিত।
টিম বাথ

1
এটি স্থির পদ্ধতি ছাড়া সহজেই করা যেতে পারে। এটা যথেষ্ট সহজ। এটি কীভাবে করা যায় সে সম্পর্কে আমি একটি সাধারণ উদাহরণের জন্য যাচ্ছিলাম।
অ্যাশথেকিং

আমি আপনার বক্তব্যটি পেয়েছি, একটি ক্ষেত্রে সুপার ভেরিয়েবল সংরক্ষণ করা এটি সমাধানের এক উপায় solve তবে, আপনার যদি ভেরিয়েবলের দরকার হয় না যদি এটি একটি স্ট্যাটিক পদ্ধতি হয় তবে আপনি কেবল এটি ব্যবহার করতে পারেন। দ্বিতীয়ত, স্থির পদ্ধতিগুলির একটিতে পরিবর্তনশীল হ'ল খারাপ অভ্যাস এবং বেশিরভাগ আইডিই আপনাকে সে সম্পর্কে সতর্ক করবে। যদি আপনি আপনার উত্তর স্থির করেন, স্থিতিশীল জিনিসগুলি সরিয়ে ফেলেন, আমি আমার ডাউনটোট, কোনও অপরাধ সরিয়ে খুশী হব।
টিম বাথ

আপনি কাছাকাছি, কিন্তু আপনার কোডটি সংকলন করবে না। আপনি আপনার মূল পদ্ধতিতে স্থির প্রসঙ্গ থেকে getNumber অ্যাক্সেস করার চেষ্টা করছেন। আপনি কি আসলে এটি সংকলন করার চেষ্টা করেছেন? (এবং আপনার আল্ট্রাফু সুপারফু প্রসারিত করা উচিত নয়?)
টিম বাথ

আমি সত্যিই আপনার প্রতি নিষ্ঠুর হতে চাই না, তবে new UltraFoo.getNumber()সংকলন করব না, কারণ আপনি সেখানে বন্ধনী মিস করেছেন। যাইহোক, আমি আমার দোভোটটিকে সরিয়ে দিয়েছি, যেহেতু আপনার কোডটির ধারণাটি এখন বেশ পরিষ্কার, ধন্যবাদ!
টিম বাথ

0

আইএমও, super.super.sayYourName()জাভাতে আচরণ অর্জনের এটি একটি পরিষ্কার উপায় ।

public class GrandMa {  
    public void sayYourName(){  
        System.out.println("Grandma Fedora");  
    }  
}  

public class Mama extends GrandMa {  
    public void sayYourName(boolean lie){  
        if(lie){   
            super.sayYourName();  
        }else {  
            System.out.println("Mama Stephanida");  
        }  
    }  
}  

public class Daughter extends Mama {  
    public void sayYourName(boolean lie){  
        if(lie){   
            super.sayYourName(lie);  
        }else {  
            System.out.println("Little girl Masha");  
        }  
    }  
}  

public class TestDaughter {
    public static void main(String[] args){
        Daughter d = new Daughter();

        System.out.print("Request to lie: d.sayYourName(true) returns ");
        d.sayYourName(true);
        System.out.print("Request not to lie: d.sayYourName(false) returns ");
        d.sayYourName(false);
    }
}

আউটপুট:

Request to lie: d.sayYourName(true) returns Grandma Fedora
Request not to lie: d.sayYourName(false) returns Little girl Masha


আহা, সুতরাং আপনি কি এভাবে শ্রেণিক শ্রেণিবিন্যাস বাস্তবায়নের পক্ষে পরামর্শ দিচ্ছেন? দুর্ভাগ্যক্রমে, আপনি যদি বাচ্চা (কন্যার সাবক্লাস) থেকে মামার পদ্ধতিটি অ্যাক্সেস করতে চান তবে এটি সত্যিই অগোছালো হতে শুরু করে ...
বিসিআর

ইয়াকভ বেহুদা ঠিক অন্য কথায়, এটি একটি ভাল উদাহরণ নয়, কারণ আসল প্রশ্নটি সুপার.সুপারে একটি ওভাররাইড পদ্ধতি কল করার বিষয়ে ছিল।
inor

0

আমি মনে করি এটি উত্তরাধিকার চুক্তি ভঙ্গকারী একটি সমস্যা।
আপনি তার শ্রেণীর আচরণকে সম্মত / সম্মত করেন এমন কোনও শ্রেণি বাড়িয়ে, বৈশিষ্ট্যগুলি
কল করার সময় super.super.method(), আপনি নিজের বাধ্যতার চুক্তিটি ভঙ্গ করতে চান।

আপনি কেবল সুপার ক্লাস থেকে চেরি নিতে পারবেন না

তবে, পরিস্থিতিগুলি ঘটতে পারে যখন আপনি কল করার প্রয়োজন বোধ করেন super.super.method()- সাধারণত আপনার কোডে বা আপনার উত্তরাধিকারী কোডটিতে একটি খারাপ ডিজাইন সাইন!
যদি সুপার এবং সুপার সুপার ক্লাসগুলি রিফ্যাক্ট করতে না পারে (কিছু লিগ্যাসি কোড), তবে উত্তরাধিকারের চেয়ে কমপোজিশনের জন্য বেছে নিন।

এনক্যাপসুলেশন ব্রেকিং যখন আপনি @ এনক্যাপসুলেটেড কোডটি ভেঙে কিছু পদ্ধতি ওভাররাইড করেন। ওভাররাইড না করার জন্য নকশা করা পদ্ধতিগুলি চূড়ান্ত হিসাবে চিহ্নিত ।


0

সি # তে আপনি এই জাতীয় কোনও পূর্বপুরুষের পদ্ধতিতে কল করতে পারেন:

public class A
    internal virtual void foo()
...
public class B : A
    public new void foo()
...
public class C : B
    public new void foo() {
       (this as A).foo();
    }

এছাড়াও আপনি এটি ডেলফিতে করতে পারেন:

type
   A=class
      procedure foo;
      ...
   B=class(A)
     procedure foo; override;
     ...
   C=class(B)
     procedure foo; override;
     ...
A(objC).foo();

তবে জাভাতে আপনি কেবল কিছু গিয়ার দ্বারা এই জাতীয় ফোকাস করতে পারেন। একটি সম্ভাব্য উপায় হ'ল:

class A {               
   int y=10;            

   void foo(Class X) throws Exception {  
      if(X!=A.class)
         throw new Exception("Incorrect parameter of "+this.getClass().getName()+".foo("+X.getName()+")");
      y++;
      System.out.printf("A.foo(%s): y=%d\n",X.getName(),y);
   }
   void foo() throws Exception { 
      System.out.printf("A.foo()\n");
      this.foo(this.getClass()); 
   }
}

class B extends A {     
   int y=20;            

   @Override
   void foo(Class X) throws Exception { 
      if(X==B.class) { 
         y++; 
         System.out.printf("B.foo(%s): y=%d\n",X.getName(),y);
      } else { 
         System.out.printf("B.foo(%s) calls B.super.foo(%s)\n",X.getName(),X.getName());
         super.foo(X);
      } 
   }
}

class C extends B {     
   int y=30;            

   @Override
   void foo(Class X) throws Exception { 
      if(X==C.class) { 
         y++; 
         System.out.printf("C.foo(%s): y=%d\n",X.getName(),y);
      } else { 
         System.out.printf("C.foo(%s) calls C.super.foo(%s)\n",X.getName(),X.getName());
         super.foo(X);
      } 
   }

   void DoIt() {
      try {
         System.out.printf("DoIt: foo():\n");
         foo();         
         Show();

         System.out.printf("DoIt: foo(B):\n");
         foo(B.class);  
         Show();

         System.out.printf("DoIt: foo(A):\n");
         foo(A.class);  
         Show();
      } catch(Exception e) {
         //...
      }
   }

   void Show() {
      System.out.printf("Show: A.y=%d, B.y=%d, C.y=%d\n\n", ((A)this).y, ((B)this).y, ((C)this).y);
   }
} 

objC.DoIt () ফলাফল আউটপুট:

DoIt: foo():
A.foo()
C.foo(C): y=31
Show: A.y=10, B.y=20, C.y=31

DoIt: foo(B):
C.foo(B) calls C.super.foo(B)
B.foo(B): y=21
Show: A.y=10, B.y=21, C.y=31

DoIt: foo(A):
C.foo(A) calls C.super.foo(A)
B.foo(A) calls B.super.foo(A)
A.foo(A): y=11
Show: A.y=11, B.y=21, C.y=31

সি # তে এটি কেবল অ-ভার্চুয়াল পদ্ধতির জন্য কাজ করবে এবং যেহেতু জাভাতে সমস্ত পদ্ধতি ভার্চুয়াল, এটি আসলে কোনও আলাদা নয়।
এজেন্ট_এল

0

এটি করা সহজ। এই ক্ষেত্রে:

এ এর বি এবং বি উপক্লাসের সি উপক্লাস তিনটির উভয়েরই পদ্ধতি পদ্ধতি নাম () রয়েছে।

public abstract class A {

    public void methodName() {
        System.out.println("Class A");
    }

}

public class B extends A {

    public void methodName() {
        super.methodName();
        System.out.println("Class B");
    }

    // Will call the super methodName
    public void hackSuper() {
        super.methodName();
    }

}

public class C extends B {

    public static void main(String[] args) {
        A a = new C();
        a.methodName();
    }

    @Override
    public void methodName() {
        /*super.methodName();*/
        hackSuper();
        System.out.println("Class C");
    }

}

রান ক্লাস সি আউটপুট হবে: ক্লাস এ ক্লাস সি

আউটপুট পরিবর্তে: ক্লাস এ ক্লাস বি ক্লাস সি


-1
public class SubSubClass extends SubClass {

    @Override
    public void print() {
        super.superPrint();
    }

    public static void main(String[] args) {
        new SubSubClass().print();
    }
}

class SuperClass {

    public void print() {
        System.out.println("Printed in the GrandDad");
    }
}

class SubClass extends SuperClass {

    public void superPrint() {
        super.print();
    }
}

আউটপুট: গ্র্যান্ডড্যাডে মুদ্রিত


2
এই উত্তরটি প্রশ্নের ক্ষেত্রের বাইরে। ওপিতে দাদা-পিতামহ শ্রেণিতে কোনও পদ্ধতিকে কীভাবে কল করা যায় তা জিজ্ঞাসা করেনি। super.super.method()জাভাতে বৈধ কোড কেন নয় তা এই বিষয়টি নিয়ে আলোচনা ।
জেদ স্কাফ

-1

কীওয়ার্ড সুপার হ'ল সুপারক্লাসে পদ্ধতিটি শুরু করার এক উপায়। জাভা টিউটোরিয়ালে: https://docs.oracle.com/javase/tutorial/java/IandI/super.html

যদি আপনার পদ্ধতিটি এর সুপারক্লাসের কোনও একটি পদ্ধতির ওভাররাইড করে তবে আপনি কীওয়ার্ড সুপারের মাধ্যমে ওভাররাইড পদ্ধতিতে অনুরোধ করতে পারেন।

বিশ্বাস করবেন না যে এটি সুপার অবজেক্টের একটি রেফারেন্স !!! না, এটি সুপারক্লাসে পদ্ধতিগুলি চাওয়ার জন্য কেবল একটি কীওয়ার্ড।

এখানে একটি উদাহরণ:

class Animal {
    public void doSth() {
        System.out.println(this);   // It's a Cat! Not an animal!
        System.out.println("Animal do sth.");
    }
}

class Cat extends Animal {
    public void doSth() {
        System.out.println(this);
        System.out.println("Cat do sth.");
        super.doSth();
    }
}

আপনি যখন কল করবেন তখন ক্লাসের cat.doSth()পদ্ধতিটি মুদ্রণ করবে এবং এটি একটি বিড়াল।doSth()Animalthis

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.