アクセス修飾子を強める方向でオーバーライドできたとしても、
アクセス修飾子はインスタンスでなく、クラスの型に依存するため、
オブジェクト指向のポリモーフィズムは破綻しないと考えます。
どういった設計思想に基づき、アクセス修飾子が強制されているのでしょうか?
強制しなくても、リスコフの置換原則は満たされませんか?
理解できなかったので、教えてください。
<参考ソース>
//アクセス修飾子はクラスの型に依存する
//public ArrayList.clone
new java.util.ArrayList().clone();
//protected Object.clone
//Compile Error
//The method clone() from the type Object is not visible
//((Object)new java.util.ArrayList()).clone();
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答5件
0
アクセス修飾子は強制ではありませんが、他回答でコメントされている意図に沿い、広い方向へのオーバーライドを考えてみましょう
ObjectとArrayListの例の通り、可視性はprotected->publicと緩和されますが、これはアクセスできる範囲を広げます
オーバーライドされたメソッドは、派生クラスの実装で上書きされますが、これは表現を変えれば派生クラスのインスタンスへのアクセスを強制すると言うことです
オーバーライドの目的は基底クラスのメソッドを無視することなので、派生クラスのメソッドはどこからアクセスされても不都合がないと言えます
一方で派生クラスへのアクセスを強制する目的で捉えた場合、基底クラスのメソッドに簡単にアクセスされては困ります
public->protectedの方向で考えた場合、基底クラスへのアクセスはどこからでも可能ですが、派生クラスへのアクセスはpublicよりも狭い範囲になります
オーバーライドはアクセス先を強制はしますが、一方で基底クラスへのアクセスを禁止しません
アップキャストを行えば容易に基底クラスのメソッドを宣言できます
これはメソッドへのアクセスが派生と基底で別れて管理されていることの証です
仮に基底クラスの方がアクセス範囲が広ければ、その範囲の網羅する場所では基底クラスのメソッドが優先され、逆に限定的な範囲では派生クラスのメソッドが選択されることになります
public->protectedの場合はオーバーライドが派生クラス自体とそれを継承する子、あるいはパッケージ内のクラスに限定されるでしょう
これが置換原則を保っているか?と問われれば「アクセス元の場所によって実装の適用元が変化する」という意味で破綻しています
とりわけ抽象メソッドとなれば実装を持たないので、そのメソッドは使えなくなってしまいます
オーバーライドは、派生クラスのメソッドが基底クラスのメソッドのアクセス範囲をカバーする責務があるということです
ちなみにこのような狭い方向へのオーバーライドをコンパイラは「弱いアクセス権限」と呼んでいます
投稿2024/03/06 03:30
総合スコア25
0
「ポリモーフィズムが破綻するしない」とか「リスコフの置換原則を満たす満たさない」とかとは別の話として、事実上アクセス範囲が狭くならない ならそれができることになんの意味がありますか?
これを許したら
「プログラマがアクセス範囲が狭くしたつもりになっているが実際はアクセス可能」
という事態を引き起こす、バグの温床になるだけの価値がない仕様になりませんか?
(質問で返してすみませんが、なんの意味があるの? というのが率直な感想です。有効な反論がないなら「アクセス修飾子を強める方向にオーバーライドできること」に価値があるとは思えません。「害しか生まない仕様になるから禁止」ではなかろうかと感じました)
投稿2024/03/06 01:18
編集2024/03/06 01:42総合スコア11299
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

退会済みユーザー
2024/03/06 04:41

退会済みユーザー
2024/03/06 08:23 編集

退会済みユーザー
2024/03/06 16:09 編集

0
自己解決
アクセス修飾子に関して、
コンパイル時は、クラスの型でアクセス可否が判定されますが、実行時は、インスタンスでアクセス可否が判定されるようです。
<参考ソース>
package packageA;
public class packageA {
void method() {
}
}
package packageB;
interface interface0 {
default void method() {
}
}
public class packageB extends packageA.packageA implements interface0 {
public static void main(String[] args) {
// Runtime Error
// Exception in thread "main"
// java.lang.IllegalAccessError:
// 'void packageB.packageB.method()'
((interface0) new packageB()).method();
}
}
投稿2024/05/27 16:32
編集2024/05/27 16:34総合スコア42
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
Javaでは、メソッドの定義にアクセス修飾子を強制しません
オーバーライド可能な対象は、可視性がprivateではないメソッドです
Java
1import java.util.*; 2 3public class Main { 4 public static void main(String[] args) { 5 Base base=new Sub(); 6 base.test(); 7 } 8} 9 10abstract class Base{ 11 abstract void sample(); 12 13 public void test(){ 14 this.sample(); 15 } 16} 17 18class Sub extends Base{ 19 @Override 20 void sample(){ 21 System.out.println("class Sub"); 22 } 23}
class Sub
アクセス修飾子を持たないメソッドは package private
として管理され、パッケージ内からのみ参照可能です
以上の通り、アクセス修飾子による修飾は任意です
オーバーライドは外部から呼び出されたメソッドの振る舞いを変更するため、インスタンス外からの参照を禁止するprivateな実装はサポートされません
投稿2024/03/06 00:46
総合スコア122
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
((Object)new java.util.ArrayList()).clone();
はObject
型としてみたときにclone()
が見えるかを判断します。
オーバーライドの成否は関係なく、Object
のclone
はそのスコープから見えないのでエラーになっています
java
1Object hoge = new java.util.ArrayList(); 2hoge.clone();
と分解すればわかりやすいでしょうか、hoge
の中身は確かにArrayList
ですが、
変数としての型はあくまでObject
なので、メソッドの可視性はObject
として判断します。
java アクセス修飾子を強める方向でオーバーライドできないのはなぜでしょうか?
いいえ、できます。
「強める」は「より広い公開範囲に」という意味と解釈しましたが、
protected
なObject::clone()
に対してpublic
なArrayList.clone()
が用意されている時点でオーバーライドはできています。
投稿2024/03/05 22:28
編集2024/03/06 00:01総合スコア13553
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2024/03/06 05:04
2024/03/06 07:35
2024/03/06 08:40
2024/03/06 09:37
2024/03/06 12:35
2024/03/07 13:42 編集
2024/03/12 13:42 編集
2024/03/13 14:44