この記事は前の記事からの続きです:java - オブジェクト指向の詳細な入門 (1)
11. 親クラスへのサブクラスのアクセスとメソッドのオーバーライド
サブクラスは親クラスのプライベート メンバーに直接アクセスできません。
ただし、サブクラスは親クラスの非プライベート メソッドを呼び出して、親クラスのプライベート メンバーに間接的にアクセスできます。親クラス。
Person クラスにはプライベート フィールド名があり、Student は Person を継承します
new Sudent().name;
サブクラスは、親クラス (サブクラスは親クラスの特殊なケースです)
メソッド オーバーライドの原因:
(一緒に):メソッドのシグネチャは同じである必要があります;(2 つの小さい):サブクラス メソッドの戻り値の型は、親クラス メソッドの戻り値の型 小さいか等しい サブクラス メソッド宣言によってスローされる例外は、親クラス メソッドによってスローされる例外と同じか小さい必要があります;(Big):サブクラス メソッドのアクセス許可は、親クラス メソッド以上である必要があります。
サブクラスは、親クラス メソッドをオーバーライドする必要があります。
12. スーパー キーワードと親クラス コンストラクターの呼び出し
#親クラス オブジェクトのデフォルトの参照を示します
If子クラスが親クラスのオーバーライドされたインスタンス メソッドを呼び出したい場合、親クラスのオーバーライドされたインスタンス メソッドを呼び出すための呼び出し元として super を使用できます。
super を使用して親クラスのメソッドを呼び出すsuper を使用して親クラスのコンストラクターを呼び出すコンストラクターの呼び出し
これ (パラメーター リスト) を使用して、このクラス内の別のオーバーロードされたコンストラクターを呼び出します。
クラス コンストラクターの場合親クラスのコンストラクターを呼び出します。super (パラメーター リスト) を使用します。
サブクラスが親クラスのコンストラクターを呼び出す場合:
super は最初の文に配置する必要があります
Java は、サブクラスのコンストラクターを実行する前に、まず親クラスのパラメーターなしのコンストラクターを呼び出します。その目的は、親クラスから継承したメンバーを初期化することです。
サブクラスはオブジェクトを作成するとき、デフォルトで親クラスのパラメータなしのコンストラクタを呼び出します。サブクラスのコンストラクタが他の親クラスのコンストラクタを呼び出すことを明示的に指定している場合は、指定された親クラスのコンストラクタが呼び出されます。親クラスのパラメーターなしのコンストラクターを呼び出します。
Eg: package reviewDemo; class A{ String name; A(){ System.out.println("父类默认隐式的构造方法!"); } A(String name){ System.out.println("父类显式的构造方法!"); } } class B extends A{ B(){ super(null); System.out.println("子类默认隐式的构造方法!"); } } public class Demo10 { public static void main(String[] args) { new B(); } }
13. オブジェクト指向ポリモーフィズム
ポリモーフィズム: さまざまな形式を持つ同じエンティティを指します。
たとえば、麺屋に麺を食べに行って、麺が欲しいと言えば、上司は牛肉麺や卵麺などをくれるでしょう。
これは、「麺類」という意味です。 " 複数の形式があります。つまり、エンティティには複数の形式があります。
コンパイル時の型は変数の宣言時に使用される型によって決まり、実行時の型は実際に割り当てられたオブジェクトによって決まります。変数に。
コンパイル時の型と実行時の型が異なる場合、ポリモーフィズムが発生します。
例:
Premise:Student extends Person:
##person p = new Person();
Student s = new Student();
person p = new Student();//ポリモーフィズム
ポリモーフィズムを実装するメカニズム:
親クラスの参照変数は、サブクラスのインスタンス オブジェクトと呼び出されるメソッドを指すことができます。実行時のプログラムによる動的バインディングは、参照変数の型で定義されたメソッドではなく、参照変数が指す実際のインスタンス オブジェクトのメソッド、つまりメモリ内で実行されているオブジェクトのメソッドを参照します。 。ポリモーフィズムの役割:
異なるサブクラス オブジェクトを親クラスとして扱うことで、異なるサブクラス オブジェクト間の差異を保護し、変化するニーズに適応する共通のコードと共通のプログラミングを作成できます。 。 メソッドの宣言ではなく、メソッドの実装のみを変更してください継承はポリモーフィズムの前提条件です;
カテゴリ:コンパイル時多態性: メソッドのオーバーロード実行時多態性: メソッドの上書き
Eg: package test; class Dog{ void eat(){ System.out.println("一般的狗吃一般的狗粮!"); } } class HashDog extends Dog{ void eat(){ System.out.println("哈士奇吃哈士奇的狗粮!"); } } class ZangAoDog extends Dog{ void eat(){ System.out.println("藏獒吃藏獒的狗粮!"); } } //定义一个动物园喂的方法 class Zoo{ void feed(Dog d){ d.eat(); } } public class Demo11 { public static void main(String[] args) { Dog hd = new HashDog(); Dog zd = new ZangAoDog(); Zoo z = new Zoo(); z.feed(hd); z.feed(zd); } }出力:ハスキー犬はハスキーなドッグフードを食べます。 チベタン・マスティフはチベタン・マスティフのドッグフードを食べます!
14. 参照変数の型変換
上方変換(サブクラス→親クラス): (自動完了) 親クラス名 親クラスのオブジェクト =サブクラス インスタンス; ダウンキャスト (親クラス→サブクラス): (強制完了) サブクラス名 subclass object = (サブクラス名) 親クラス インスタンス; オブジェクト名 クラスのインスタンス この時点で指定された変数名によって参照される実際の型が、現在指定されているクラスまたはサブクラスであるかどうかを判断します; 私の要約: オブジェクトの型とクラスには継承関係が必要ですEg: class A extends B{} B b = new A(); If(b instanceof A){ ... }
2、面向对象(2)
1、基本数据类型的包装类
引言:Java提倡的万物皆对象,但是数据类型的划分出现了基本数据类型和引用数据类型,那么我们怎么能把基本数据类型称为对象呢?
除了Integer和Character定义的名称和对应的基本类型差异大,其他六种都是将首字母大写就可以了。
Integer,Byte,Float,Double,Short,Long都是Number类的子类。(Number类后面讲);
Character和Boolean都是Object直接子类;
8个类都是final修饰的(不可被继承)。
2、基本数据类型和包装类相互转换
把基本数据类型 → 包装类:
通过对应包装类的构造方法实现
除了Character外,其他包装类都可以传入一个字符串参数构建包装类对象。
包装类 → 基本数据类型
包装类的实例方法xxxValue(); // xxx表示包装类对应的基本数据类型
Eg: boolean bool = false; Boolean b2 = new Boolean(bool); Integer i = new Integer(3); int i2 = i.intValue(); Boolean b1 = new Boolean("TRue");//true boolean b2 = b1.booleanValue(); Float f = new Float("3.14");//3.14 Integer i2 = new Integer("123s");//NumberFormatException
备注:
自动装箱&自动拆箱
jdk1.5开始出现的特性:
自动装箱:可把一个基本类型变量直接赋给对应的包装类对象或则Object对象
自动拆箱:允许把 包装类对象直接赋给对应的基本数据类型
Eg: Integer i = 3;//装箱 int i2 = i;//拆箱 Object flag = new Boolean(false); if(flag instanceof Boolean){ Boolean b = (Boolean)flag; boolean b2 = b; }
3、基本类型和String之间的转换
String → 基本类型,除了Character外所有的包装类提供parseXxx(String s)静态方法,用于把一个特定的字符串转换成基本类型变量;
基本类型 → String,String 类有静态方法valueOf(),用于将基本类型的变量转换成String类型。
String str = "17"; int i = Integer.parseInt(str);//String --> 基本类型 String s1 = String.valueOf(i);//基本类型 --> String
4、Object类
所有类的公共父类,一旦一个类没有显示地继承一个类则其直接父类一定是Object。
一切数据类型都可用Object接收
class OOXX extends Object{}等价于class ooXX {}
常见方法
public boolean equals(Object obj)
:对象比较
public int hashCode()
:取得该对象的Hash码
public String toString()
:对象描述
Object类的 toString()方法:“对象的描述”
建议所有类都覆写此方法
直接打印输出对象时,会调用该对象的toString()方法。//可以不写出来
打印对象的时候,实际调用的对象实际指向的类的自我描述;
全限定类名+@+十六进制的hashCode值,等价于
全限定类名+@+IntegertoHexString(该对象.hashCode)
equals也是判断是否指向同一个对象
没有实际意义,有必要可以重写
public boolean equals(Object obj) {}
String 覆写了 Object的equals方法:只比较字符的序列是否相同
==用于判断两个变量是否相等
基本类型:
引用类型:必须指向同一个对象,才true
只能比较有父子或平级关系的两个对象
new String("1") == new String("1"); ?
5、代码块
代码块指的是使用"{}"括起来的一段代码,根据代码块存在的位置可以分为4种:
普通代码块;
构造代码块;
静态代码块;
同步代码块(线程同步的时候讲解)。
代码块里变量的作用域:
只在自己所在区域(前后的{})内有效;
普通代码块:
普通代码块就是直接定义在方法或语句中定义的代码块:
public void show(){
普通代码块
}
构造代码块:
直接写在类中的代码块:
优先于构造方法执行,每次实例化对象之前都会执行构造代码块。
Eg: public class Demo { { System.out.println("我是构造代码块"); } public Demo(){ System.out.println("我是构造方法"); } public static void main(String[] args) { Demo d1 = new Demo(); Demo d2 = new Demo(); } }
静态代码块
使用static 修饰的构造代码块:
优先于主方法执行,优先于构造代码块执行,不管有创建多少对象,静态代码块只执行一次,可用于给静态变量赋值;
Eg: package reviewDemo; /** * 测试各代码块的优先级 * 优先级顺序:静态代码块 > 构造代码块 > 普通代码块 * 备注:无论创建几个对象,静态代码块只执行一次! */ public class Demo13 { Demo13(){ System.out.println("我是构造方法!"); } { System.out.println("我是构造代码块!");//实例化对象的时候才会去调用! } static{ System.out.println("我是静态代码块!"); } public static void main(String[] args) { new Demo13(); new Demo13();//再次创建对象,证明无论创建几次对象,静态代码块都只执行一次 System.out.println("我是普通代码块!"); } }
输出:
我是静态代码块!
我是构造代码块!
我是构造方法!
我是构造代码块!
我是构造方法!
我是普通代码块!
6、构造方法的私有化
有的时候我们为了避免外界创建某类的实例,就将某类的构造方法私有化,即将它的构造方法用private修饰:
外界如何用到?
提供get方法!不提供的话外界就没法创建对象!(对反射无效)
Eg:package reviewDemo; class Stu{ //将构造方法私有化 private Stu(){ } } public class Demo15 { public static void main(String[] args) { Stu s = new Stu(); } }
Singleton模式(单例模式) 饿汉式和懒汉式
目的:整个应用中有且只有一个实例,所有指向该类型实例的引用都指向这个实例。
好比一个国家就只有一个皇帝(XXX),此时每个人叫的“皇帝”都是指叫的XXX本人;
常见单例模式类型:
饿汉式单例:直接将对象定义出来
懒汉式单例:只给出变量,并不将其初始化;
我的总结:
饿汉式,static修饰,随着类的加载而加载,会损耗性能,但是方法相对简单
懒汉式 第一次用的时候相对较慢,因为需要加载!线程,不安全!
package reviewDemo; //单例模式 //饿汉式,直接把对象构造出来 class SingleDemo{ private static SingleDemo s1 = new SingleDemo(); private SingleDemo(){ //提供私有化的构造方法,那么外界就不能构造对象了! } public static SingleDemo getS1() { return s1; } } //懒汉式,先定义,但是不创建对象 class SingleDemo2{ private static SingleDemo2 s3 ; private SingleDemo2(){ //提供私有化的构造方法,那么外界就不能构造对象了! } public static SingleDemo2 getS3() {//这是一个方法,返回值为创建的对象! if(s3 == null){ s3 = new SingleDemo2(); }//和饿汉式的区别,此时才来创建对象! return s3; } } public class Demo14 { public static void main(String[] args) { SingleDemo s1 = SingleDemo.getS1(); SingleDemo s2 = SingleDemo.getS1(); SingleDemo2 s3 = SingleDemo2.getS3(); SingleDemo2 s4 = SingleDemo2.getS3(); System.out.println(s1 == s2); System.out.println(s3 == s4); } } 输出:true true 备注:枚举更加安全些 package reviewDemo; enum Stu{ jake; //将构造方法私有化起来,反射也不能创建对象,安全 private Stu(){ } } public class Demo15 { public static void main(String[] args) { } }
8、final 关键字
final可以修饰类,方法,变量。
final修饰类不可以被继承,但是可以继承其他类。
final修饰的方法不可以被覆写,但可以覆写父类方法。
final修饰的变量称为常量,这些变量只能赋值一次。
内部类在局部时,只可以访问被final修饰的局部变量。
final修饰的引用类型变量,表示该变量的引用不能变,而不是该变量的值不能变;
Eg: package reviewDemo; final class Name{ } class NewName extends Name{//ERROR,报错,因为Name有final修饰 } public class Demo15 { public static void main(String[] args) { } }
9、抽象类
当编写一个类时,我们往往会为该类定义一些方法,这些方法是用来描述该类的行为方式,那么这些方法都有具体的方法体。
但是有的时候,某个父类只是知道子类应该包含怎么样的方法,但是无法准确知道子类如何实现这些方法。
抽象方法的定义:通过abstract关键字来修饰的类称为抽象类;
总结:抽象类用private修饰,里面可以有用private修饰的方法(没有方法体),强制子类进行覆写;
可以理解为:具有某些公共方法的一个总结类。
可以定义被abstract修饰的抽象方法
抽象方法只有返回类型和方法签名,没有方法体。
备注:
抽象类可以含有普通方法
抽象类不能创建实例对象(不能new)
需要子类覆盖掉所有的抽象方法后才可以创建子类对象,否则子类也必须作为抽象类
列举常见的几个抽象类:
流的四个基本父类
InputStream,OutputStream,Reader,Writer
我的总结:
抽象类是类的一种特殊情况:据有类的一切特点,但是不能实例化;一般的都得带有抽象方法。
抽象类不可以实例化,有时看到的近似实例化是多态机制的体现,并不是真正的实例化。
Eg: Socket s = new Socket(); OutputStream os = s.getOutputStream(); 左边是OutputStream类型变量的声明,右边是获取抽象类OutputStream的一个实例对象! package testDemo2; abstract class Person{ } class Student extends Person{ } public class Demo2 { public static void main(String[] args) { Person p = new Student();//体现的是多态,父类声明实例化子类对象。而不是抽象类实例化 } }
abstract方法
分析事物时,发现了共性内容,就出现向上抽取。会有这样一种特殊情况,就是功能声明相同,但功能主体不同。
那么这时也可以抽取,但只抽取方法声明,不抽取方法主体。那么此方法就是一个抽象方法。
abstract [非private访问修饰符] 返回值类型 方法名称(参数列表);
抽象方法要存放在抽象类中。
抽象方法也可以存在于接口中
Eg: package reviewDemo; abstract class Person3{ abstract void show(); abstract void inof(); void turn(){ } } class NewP extends Person3{ @Override void show() { } @Override void inof() { } //不覆写的话会报错 } public class Demo15 { public static void main(String[] args) { //new Person3();报错!因为抽象类不可以实例化 } }
10、抽象类的体现-模板模式
抽象类是多个具体子类抽象出来的父类,具有高层次的抽象性;以该抽象类作为子类的模板可以避免子类设计的随意性;
抽象类的体现主要就是模板模式设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行拓展,但是子类在总体上大致保留抽象类的行为方式;
编写一个抽象父类,该父类提供了多个子类的通用方法,并把一个或多个抽象方法留给子类去实现,这就是模板设计模式;
模板模式应用的简单规则:
1.抽象父类可以只定义需要使用的某些方法,其余留给子类去实现;
2.父类提供的方法只是定义了一个通用算法,其实现必须依赖子类的辅助;
我的总结:
如果父类的方法不想被子类覆写,那么可以在前面加上final关键字修饰。
Eg: package reviewDemo; //模板模式 //抽象类中包含很多的抽象方法,子类必须去覆写! abstract class Method{ abstract double mul();//返回值类型如果是void的话,下面报错,因为没有返回值,无法引用! abstract double divid(); void show(){ System.out.println("面积是:"+mul());//周长 System.out.println("面积是:"+divid());//面积 } } class Square extends Method{ double d; public Square(double d) { super(); this.d = d; } @Override double mul() { return d * d; } @Override double divid() { return 4 * d; } } class Cirle extends Method{ double r; public Cirle(double r) { super(); this.r = r; } @Override double mul() { return 2 * 3.14 * r; } @Override double divid() { return 3.14 * r * r; } } public class Demo16 { public static void main(String[] args) { Square s = new Square(5); s.show(); Cirle c = new Cirle(4); c.show(); } }
以上是本次整理的关于java面向对象的详细讲解,后续会为大家继续整理。
文中若有明显错误请指正,谢谢!
JAVA 関連のその他の質問については、PHP 中国語 Web サイトを参照してください: JAVA ビデオ チュートリアル
以上がJava——オブジェクト指向の詳しい入門 (2)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。