1 Day06 – オブジェクト指向 1
1.1 オブジェクト指向
1.1.1 コンセプト
おすすめの本:Javaで考える
コンセプト: いわゆるオブジェクト指向は、元の実行者から指揮者に至るまで、人生の複雑なことを単純化できるプログラミングの考え方です。オブジェクト指向はプロセス指向に基づいています。
プロセス指向の構造化設計の長所と短所:
1). 短所: データのカプセル化の欠如。
2). 欠点: データとメソッド (データを操作するための) を分離するのが困難です。
3). 利点: 比較的高いパフォーマンス。
オブジェクト指向設計の長所と短所:
1). 長所: 保守が容易、拡張が容易、再利用が容易です。
2). 欠点: パフォーマンスはプロセス指向よりも低くなります。
プロセス指向はプロセスを強調します。例:
1. 冷蔵庫を開ける 2. 象を入れる 3. 冷蔵庫を閉める
オブジェクト指向は結果を重視します、例:
1. お腹が空いたらプラットフォームに行って食べ物を注文する、このアクションはオブジェクト指向です。市場に行って野菜を買ったり、洗ったり、調理したりするわけではありません。。。アプリがある限り。
2. 服が汚れている場合は、女性に対処を任せて、きれいな服を着るのを待ちます。途中の過程には注意が払われません。。ただ良いパートナーを見つけてください。
3. インタビュアーは、オブジェクト指向とは何ですか?と尋ねました。あなたは、すべてがオブジェクトであると答えます。!まだここまで深く理解していないのでお勧めしませんが、例を挙げることをお勧めします。空虚は形であり、形は空であるとあなたが言うなら、それを信じてください、というようなものです。
私たちがよく言うことオブジェクト指向プログラミング成し遂げる(OOP,オブジェクト指向プログラミング)
オブジェクト指向の本質は、コードをクラスの形式で編成し、データをオブジェクトの形式でカプセル化することです。
1.1.2 3つの大きな特徴
1. カプセル化: カプセル化によりソフトウェアコンポーネントの「高凝集性・低結合性」を実現し、依存関係によるプログラム変更の影響を防ぎます。
(1) クラス: オブジェクトのプロパティと動作をカプセル化します。
(2) メソッド: 特定のビジネス ロジック関数の実装をカプセル化します。
(3) アクセス制御修飾子: 特定のアクセス権をカプセル化します。
2. 継承: 継承により、ソフトウェアの再利用性と拡張性が向上します。
(1) 機能:コードの再利用の促進、コードの冗長性の削減、プログラムの保守性と拡張性の向上
(2) スーパークラス:すべての派生クラスに共通の属性と動作インターフェイス:
一部の派生クラスに共通の
動作の派生 クラス:派生クラスに固有の属性と動作クラス
(3) クラス間には単一の継承、インターフェイス間には多重継承、クラスとインターフェイス間には複数の実装があります。
3. ポリモーフィズム: ポリモーフィズムは、ソフトウェアの柔軟性と拡張性を強化します。
(1) 分類:
(1.1) 動作多態性 (例を挙げることができます)
(1.2) オブジェクト多態性 (例を挙げることができます)
(2) アップキャスト、強制型変換、インスタンスオブジャッジメント
(3) 多態性表現
(3.1) 書き換え: 多態性を次のように表現します。異なるオブジェクト
(3.2) オーバーロード: 異なるパラメータに従って多態性を表現する
1.1.3 拡張: 値渡しと参照渡し
仕様: プロジェクトにはメインのスタートアップ クラスが 1 つだけ必要です
Javaは値渡しです。
package com.shuai;
public class Demo01 {
//值传递
public static void main(String[] args) {
int a = 1;
System.out.println(a);//1
change(a);
System.out.println(a);//1 没有修改成功
}
public static void change(int a) {
//返回值为空,就没有返回值
a=10;
}
}
1.2 クラスとオブジェクト
1.2.1 クラス
1. Java言語が最も重要基本単位これは型に似たクラスです。
2. クラスは、あるタイプの抽象化です。(個人のタイプを表すカテゴリ/タイプ) 3.テンプレートまたは設計図
として理解できます。4. 同じパッケージ内のクラスは相互に使用できますが、同じ名前を持つことはできません (保存する必要があります)。5.構文: class クラス名 { } 6.クラスには通常、以下が含まれます。
- すべてのオブジェクトに共通のプロパティ/特性------メンバー変数
- すべてのオブジェクトに共通の動作 ------- メソッド
同じパッケージ内のクラスには直接アクセスできますが、異なるパッケージ内のクラスには直接アクセスできません。
- まず import で完全な名前のクラス (パッケージ名 + クラス名) を宣言し、次にそのクラスにアクセスします (つまり、新しいオブジェクト)。
- クラスの完全名にアクセスする ------- は面倒すぎるため推奨されません (ステートメントを 1 つずつ記述するのは面倒です)
注: .java ファイルには複数のクラスを含めることができますが、パブリックに変更されたクラスは 1 つだけである必要があり、クラス名はファイル名になります (大文字と小文字は区別され、パブリック変更するクラスは必要ありません)。変更されたクラス)。異なるファイルには複数のパブリックを含めることができ、Chu Ti を作成する場合、異なるファイルを一緒に書き込むことができるため、複数のパブリックを作成できます。
1.2.2 オブジェクト
対象: 実在する個人。
各オブジェクトには 3 つの特性があります。州、 物体行動そしてオブジェクトロゴ。
1. オブジェクトの状態は、オブジェクトの基本特性を説明するために使用されます。
2. オブジェクトの動作は、オブジェクトの機能を説明するために使用されます。
3. オブジェクトの識別とは、そのオブジェクトが他のオブジェクトと区別するためにメモリ内に固有のアドレスを持っていることを意味します。
4. クラスはあるタイプの抽象化であり、オブジェクトは具体的な実装です。
5. 構文: new class name ();
6. それぞれの new は新しいオブジェクトを作成します。
7. new キーワードを使用してオブジェクトを作成し、スペースを割り当てた後、デフォルトの初期化 (変数にデフォルト値を割り当てる) とコンストラクターの呼び出しという 2 つの処理が行われます。
メンバー変数とメソッドの呼び出し (オブジェクトの作成時) :
引用类型的名字.局部变量名 = 赋值;
引用类型的名字.方法调用的方式;
オブジェクトを作成する理由: アクセスとは、クラス内のオブジェクト、変数、メソッドにアクセスすることを意味し、インスタンス化後にのみオブジェクトをメモリに配置し、指定された範囲内で呼び出すことができるためです。
1.2.3 クラスとオブジェクトの関係
1. コンピュータ言語は、現実世界の物事を説明するために使用されます。プロパティ + 動作
2. Java 言語でどのように記述するか?クラスを通して物事を記述し、物事の属性を と見なし成员变量
、動作を と見なす成员方法
。
3. クラスは複数のオブジェクトを作成できます。
概要: クラスはオブジェクトのテンプレートであり、オブジェクトはクラスの特定のインスタンスです。
携帯電話を例に挙げます。
属性:颜色,尺寸,品牌,价格。
方法:打电话,发短信,听音乐。
类:手机类,抽取相同的属性和行为
对象:可以按照模板生产很多个手机,比如1号手机对象,包含特有的成员变量和成员方法
1.3 クラスとオブジェクトの作成と使用
1.3.1 演習 1: クラスの作成と使用
class キーワードを使用してクラスを作成し、new キーワードを使用してオブジェクトを作成します
1) 。
public class Test1_CreateObject {
public static void main(String[] args) {
//创建对象测试
//3,通过关键字new来创建对象
//new Phone()匿名对象,一次只干一个活
//new Phone().call(); 只能干一件事
//4,p是Phone类型是引用类型的变量,引用了,,,内存中的地址值
Phone p = new Phone();
//引用类型的创建,引用类型的默认值是null,引用类型与它需要实例的对象类名一致。
//p代表了Phone对象,真的能用模板定义的功能吗???
//调用方法
p.call();
p.message();
p.music();
//设置属性值
p.color="green"; //调用的时候改值
p.size=6;
p.pinpai="HUAWEI";
p.price=20000;
//调用属性
System.out.println(p.color);//null --green
System.out.println(p.size);//0 -- 6
System.out.println(p.pinpai);//null --HUAWEI
System.out.println(p.price);//0.0 --20000.0
}
}
//1,创建手机类,用来描述手机事物
//2,通常描述:事物的特征+事物的行为
class Phone{
// 事物的特征 -- 成员变量/成员属性
// 特征:颜色,尺寸,品牌,价格
String color;
int size;
String pinpai;
double price;
// 事物的行为 -- 成员方法/成员函数
// 行为/功能:打电话,发短信,听音乐
//修饰符 返回值 方法名(参数列表){方法体}
public void call() {
System.out.println("call()...");
}
public void message() {
System.out.println("message()...");
}
public void music() {
System.out.println("music()...");
}
}
2)。
package cn.tedu.oop;
//练习
public class Test2_Car {
public static void main(String[] args) {
//2,创建Car对象测试
Car c = new Car();
//调用功能
c.run();
c.stop();
//设置属性值
c.color="red";
c.model="BMW5";
c.pinpai="BMW";
//直接输出变量
System.out.println(c.color);
System.out.println(c.model);
System.out.println(c.pinpai);
}
}
//1,创建Car类,用来描述汽车事物
class Car{
// -- 特征+行为
String color;
String model;
String pinpai;
public void run() {
System.out.println("正在飞");
}
public void stop() {
System.out.println("停车");
}
}
1.3.2 メモリ内のオブジェクトの保存
Java はメモリを 5 つの主要な領域に分割します。メモリは JVM によって管理され、スタックとヒープに重点が置かれます。
- 一般に、ローカル変数はスタックに格納され、メソッドの実行後にメモリが解放されます (スタックはヒープよりも小さいです)。
- オブジェクト(新しいもの)はヒープに格納され、オブジェクトが使用されなくなるとメモリが解放されます。
- ヒープメモリの各要素にはアドレス値があります
- オブジェクト内のすべてのプロパティにはデフォルト値があります。
- アドレス値は一意であり、繰り返されません(アドレス値の保存に必要なメモリ領域とコストが少なくなります)
- スタック: 先入れ後出しの原則 (弾丸を装填するのと同様) ヒープ: この原則がなければ、どこにでも置くことができます。
- メモリは JVM によって管理されます。最初にクラスがロードされ、次に .class がメソッド領域に割り当てられ、次にヒープが割り当てられ、次にスタックが割り当てられます (スタックとヒープはほぼ同時に開始されます)。
- オブジェクトは、初期化された後にのみアドレス値を持ちます。
- スタック: メソッドの実行後に解放されます。ヒープ: 参照なしで呼び出された場合にメモリを解放します。
スタック、ヒープ、メソッド領域には何が格納されますか?
スタック: ローカル変数 (ローカル変数とも呼ばれるメソッド パラメーターを含む) は、対応するオブジェクトのアドレス値を格納します。
ヒープ: 新しいオブジェクト (インスタンス変数とメソッドを含む)。
メソッド領域: クラス内の .class バイトコード ファイル (静的メソッドおよび静的変数)。一度だけロードされます。
1.3.3 単一オブジェクトのメモリ グラフ
名詞: 飛び出す
1.3.4 演習 2: 複数のオブジェクトの作成
package cn.tedu.oop;
//测试多个对象的创建和使用
public class Test3_Person {
public static void main(String[] args) {
//创建对象测试 (addr:地址 brand:品牌)
Person p = new Person();
p.game(); //调用方法的时候可以传参赋值
p.code();
//设置属性值:在调用属性的时候赋值
p.name="rose";
p.age=20;
p.gender=1;
p.address="北京";
//打印
System.out.println(p.name);
System.out.println(p.age);
System.out.println(p.gender);
System.out.println(p.address);
/*如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性。(非static的)
意味着:如果我们修改一个对象的属性a,则不影响另外一个对象属性a的值。*/
Person p2 = new Person();
p2.code();
p2.game();
//TODO 设置属性值
System.out.println(p2.name);//null
System.out.println(p2.age);
System.out.println(p2.gender);
System.out.println(p2.address);
//p3是引用类型的变量,这里没有new,在堆内存中就不会开辟新空间。
//p3保存了p2保存着的地址值
Person p3 = p2;
}
}
//创建Person类
class Person{
//特征
String name;
int age;
int gender;//0男1女
String address;
//行为
public void code() {
System.out.println("敲代码");
}
public void game() {
System.out.println("吃鸡");
}
}
1.3.5 マルチオブジェクトメモリグラフ
1. 変数 p と変数 p2 は同じ空間ではありません。p1 は新しい空間を開く必要があります。
2. 人物 p2=新しい人物。このとき、新しいものがある限り、新しい空間が開かれ、ヒープメモリ内のオブジェクト。
1.4 梱包
1.4.1 概要
カプセル化とは、オブジェクトのプロパティと実装の詳細を隠し、外部へのパブリック アクセスのみを提供することを指します。
メリット:
1. セキュリティの向上
2. 再利用性の向上
事例:
1. クラス
2. 手法
1.4.2 プライベートキーワード
変更するために使用される権限修飾子です。メンバー変数とメンバー関数、プライベート化されたメンバーは、このクラス内でのみアクセスできます。変更したい場合は、外部から提供されているパブリックな get (値の取得) メソッドと set (代入) メソッドにのみアクセスできます。以前は を通じて代入を直接呼び出すことができましたが、現在は set を通じてのみ代入操作を実行できます对象.资源
。メソッドまたはコンストラクター メソッド。もちろん、単に呼び出したり对象.资源
呼び出したりするだけです。
このクラスのカプセル化は、private キーワードを使用して実装され、セキュリティの向上を目的としています。
例: public int age 外部世界はこれを自由に呼び出して 10,000 歳の値を割り当てることができますが、これは明らかに不合理です。プライベートで変更したい変数は、パブリック変更メソッドにアクセスすることによってのみ呼び出すことができます。メソッド内でいくつかの制限を追加することはできますが、変数に制限を追加することはできません。
一般的なカプセル化: プロパティ (メンバー変数) はプライベート化され、動作 (メソッド) は公開されます。
1.4.3 演習 1: 学生のカプセル化
学生クラスの作成と学生オブジェクトのテストの作成
package cn.tedu.oop;
//测试封装
public class Test4_Private {
public static void main(String[] args) {
//创建学生对象测试
Student s = new Student();
//调用功能
// s.study();//由于study()被private修饰了,除了自己的类,别的类都用不了
s.sleep();
// System.out.println(s.name);//由于name被private修饰了,除了自己的类,别的类都用不了
//3,如果我就是想要修改已经被private的name属性的值? --访问公共的set()
// s.name ="jack";//无法访问
s.setName("jack"); //调用set方法赋值88888888888
//4,如果外界就是想要获取被private的name属性的值? --访问公共的get()
// System.out.println(s.name) ;//无法访问
System.out.println(s.getName());//和平常的输出不一样,这个是直接输出的方法。(因为get方法有返回值一般前边是定义一个变量来接受,所以说这个地方可以直接输出方法)
}
}
//创建学生类
class Student{
//成员属性
//1.1,封装:成员变量,封装好的变量,外界无法直接访问,需要间接访问公共的set()设置值,get()获取值 有快捷键:source------get and set
private String name;
//3.1,对外提供一个公共的修改方法 -- setXxx() 没有返回值
public void setName(String n) {
//拿到n之后,需要把n的值赋值给name
name = n;
}
//4.1,对外提供一个公共的获取改方法 -- getXxx() 有返回值
public String getName(){
//4.2,通过return关键字,把name属性的值,返回给调用位置
return name;
}
//TODO 封装以下三个属性,并提供set()/get()
private String subject;
public void setSubject(String s) {
subject = s ;
}
public String getSubject() {
return subject;
}
private int sno;
private int age;
//eclipse自动生成代码:右键-source-setters and getters-select all-ok
public int getSno() {
return sno;
}
public void setSno(int sno) {
this.sno = sno;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//成员方法
//1,封装:利用private关键字实现,目的就是提高代码的安全性,被private之后,资源只能在本类中看见
private void study() {
System.out.println("正在学习");
}
public void sleep() {
//2,如果外界还是想执行study(),可以访问公共的sleep(),间接实现访问study()
study();
System.out.println("正在睡觉");
}
}
1.5 拡張
1.5.1 オブジェクトの作成プロセス
Person p = new Person();//この短いコード行では多くのことが起こります
1. Person.class ファイルをメモリにロードします
2. スタック メモリで、変数 p を格納するためのスペースを開きます
3.ヒープ メモリ、人物オブジェクトを保存するためのスペースを開く
4. メンバー変数のデフォルトの初期化
5. メンバー変数の初期化の表示
6. 構築メソッドの実行 (構築コード ブロックがある場合は、最初に構築コード ブロックを実行し、次に構築メソッドを実行します) )
7. ヒープメモリの完成
8. 変数 p にヒープメモリのアドレス値を代入します。 p は Person オブジェクトのアドレス値を参照する参照変数です。
1.5.2 匿名オブジェクト
名前のないオブジェクトは、オブジェクトを簡略化して表現したものです。
使用シナリオ: 呼び出されるオブジェクトが 1 回だけ呼び出される場合。
アドバンテージ: メモリを節約し、効率が高くなります。一度呼び出したらすぐにメモリを解放するので
欠点がある: 制限、その属性は 1 回しか使用できません。
Demo d = new Demo();
d.sleep();
d.game();
//这个d就是对象的名字。
也可以写成:
new Demo().show();//创建了一个对象调方法
new Demo().game();//又创建了一个对象调方法
1.5.3 オブジェクト型の配列の宣言
package com.atguigu.exer;
/*
* 对象数组题目:
定义类Student,包含三个属性:学号number(int),年级state(int),成绩score(int)。
创建20个学生对象,学号为1到20,年级和成绩都由随机数确定。
问题一:打印出3年级(state值为3)的学生信息。
问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
提示:
1) 生成随机数:Math.random(),返回值类型double;
2) 四舍五入取整:Math.round(double d),返回值类型long。
*
*
*
*
*/
public class StudentTest {
public static void main(String[] args) {
// Student s1 = new Student();
// Student s1 = new Student();
// Student s1 = new Student();
// Student s1 = new Student();
// Student s1 = new Student();
// Student s1 = new Student();
//声明Student类型的数组
Student[] stus = new Student[20]; //String[] arr = new String[10];
for(int i = 0;i < stus.length;i++){
//给数组元素赋值
stus[i] = new Student();
//给Student对象的属性赋值
stus[i].number = (i + 1);
//年级:[1,6]
stus[i].state = (int)(Math.random() * (6 - 1 + 1) + 1);
//成绩:[0,100]
stus[i].score = (int)(Math.random() * (100 - 0 + 1));
}
//遍历学生数组
for(int i = 0;i <stus.length;i++){
// System.out.println(stus[i].number + "," + stus[i].state
// + "," + stus[i].score);
System.out.println(stus[i].info());
}
System.out.println("********************");
//问题一:打印出3年级(state值为3)的学生信息。
for(int i = 0;i <stus.length;i++){
if(stus[i].state == 3){
System.out.println(stus[i].info());
}
}
System.out.println("********************");
//问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
for(int i = 0;i < stus.length - 1;i++){
for(int j = 0;j < stus.length - 1 - i;j++){
if(stus[j].score > stus[j + 1].score){
//如果需要换序,交换的是数组的元素:Student对象!!!
Student temp = stus[j];
stus[j] = stus[j + 1];
stus[j + 1] = temp;
}
}
}
//遍历学生数组
for(int i = 0;i <stus.length;i++){
System.out.println(stus[i].info());
}
}
}
class Student{
int number;//学号
int state;//年级
int score;//成绩
//显示学生信息的方法
public String info(){
return "学号:" + number + ",年级:" + state + ",成绩:" + score;
}
}
最適化された書き込みメソッド: 配列ツール クラスにカプセル化
package com.atguigu.exer;
/*
* 4. 对象数组题目:
定义类Student,包含三个属性:学号number(int),年级state(int),成绩score(int)。
创建20个学生对象,学号为1到20,年级和成绩都由随机数确定。
问题一:打印出3年级(state值为3)的学生信息。
问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
提示:
1) 生成随机数:Math.random(),返回值类型double;
2) 四舍五入取整:Math.round(double d),返回值类型long。
*
*
* 此代码是对StudentTest.java的改进:将操作数组的功能封装到方法中。
*
*/
public class StudentTest1 {
public static void main(String[] args) {
//声明Student类型的数组
Student1[] stus = new Student1[20];
for(int i = 0;i < stus.length;i++){
//给数组元素赋值
stus[i] = new Student1();
//给Student对象的属性赋值
stus[i].number = (i + 1);
//年级:[1,6]
stus[i].state = (int)(Math.random() * (6 - 1 + 1) + 1);
//成绩:[0,100]
stus[i].score = (int)(Math.random() * (100 - 0 + 1));
}
StudentTest1 test = new StudentTest1();
//遍历学生数组
test.print(stus);
System.out.println("********************");
//问题一:打印出3年级(state值为3)的学生信息。
test.searchState(stus, 3);
System.out.println("********************");
//问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
test.sort(stus);
//遍历学生数组
test.print(stus);
}
/**
*
* @Description 遍历Student1[]数组的操作
* @author shkstart
* @date 2019年1月15日下午5:10:19
* @param stus
*/
public void print(Student1[] stus){
for(int i = 0;i <stus.length;i++){
System.out.println(stus[i].info());
}
}
/**
*
* @Description 查找Stduent数组中指定年级的学生信息
* @author shkstart
* @date 2019年1月15日下午5:08:08
* @param stus 要查找的数组
* @param state 要找的年级
*/
public void searchState(Student1[] stus,int state){
for(int i = 0;i <stus.length;i++){
if(stus[i].state == state){
System.out.println(stus[i].info());
}
}
}
/**
*
* @Description 给Student1数组排序
* @author shkstart
* @date 2019年1月15日下午5:09:46
* @param stus
*/
public void sort(Student1[] stus){
for(int i = 0;i < stus.length - 1;i++){
for(int j = 0;j < stus.length - 1 - i;j++){
if(stus[j].score > stus[j + 1].score){
//如果需要换序,交换的是数组的元素:Student对象!!!
Student1 temp = stus[j];
stus[j] = stus[j + 1];
stus[j + 1] = temp;
}
}
}
}
}
class Student1{
int number;//学号
int state;//年级
int score;//成绩
//显示学生信息的方法
public String info(){
return "学号:" + number + ",年级:" + state + ",成绩:" + score;
}
}
2 Day07 – オブジェクト指向 2
2.1 コンストラクター (コンストラクター、ビルダー、コンストラクター、コンストラクター)
2.1.1 コンセプト
- コンストラクターは、クラスと同じ名前を持ち、戻り値( void さえも)を持たない特殊なメソッドです。通常のメソッドもクラスと同じ名前を持つことができますが、通常はこのようには記述されません。
- オブジェクトの作成はコンストラクター メソッドを通じて行われます。
- その主な機能は次のとおりです。 1. オブジェクトの作成を完了します。2. オブジェクトのプロパティを初期化できる。
- コンストラクターは、クラスがオブジェクトをインスタンス化するときに自動的に呼び出されます。
- コンストラクターは、他のメソッドと同様にオーバーロードできますが、オーバーライドすることはできません。(理由: 1. コンストラクターは継承できません。継承するとサブクラスのクラス名と同じになります。 2. サブクラスに super があるため、自動的に親クラスのコンストラクターを呼び出します。)
- コンストラクターを定義しない場合、パラメーターなしのコンストラクターがデフォルトで提供されます (したがって、どのクラスにもコンストラクターがあります)。コンストラクターを定義すると、デフォルトでは提供されなくなるため、パラメーターなしのコンストラクターを手動で作成することをお勧めします。
- コンストラクター メソッドの役割: 外部の世界によるオブジェクトの作成を容易にすること。
アイデアは、コンストラクター メソッドのショートカット キー: alt+insert を生成します。
2.1.2 フォーム
修饰符 类名([参数列表]){
//可以无参也可以有参
代码……
//没有返回值
}
2.1.3 演習 1: オブジェクトを作成するコンストラクター メソッド
package cn.tedu.constructor;
//测试构造方法的使用
public class Test5_Constructor {
public static void main(String[] args) {
//创建Teacher测试
//1,当创建对象时,会自动调用构造方法???--会自动调用,调用了默认就会存在的无参构造
Teacher t = new Teacher();
//3.1,创建对象时,触发含参构造,根据不同的参数类型来自动调用构造方法.
Teacher t1 = new Teacher("tony");
}
}
//创建Teacher类
class Teacher{
//2,提供构造方法:修饰符 类名([参数列表]){}
//4,无参构造 -- 默认就会存在 -- 前提是:没有含参构造时,才存在。如果只提供了含参构造,无参构造就真没了。
public Teacher() {
System.out.println("无参构造...");
}
//3,构造方法是一个特殊的方法,特殊在没有返回值,方法名=类名。但是可以存在方法的重载现象
//准备重载的构造方法
public Teacher(String n) {
System.out.println("含参构造..."+n);
}
}
2.1.4 演習 2: コンストラクターの初期化代入
package cn.tedu.constructor;
//这个类用来测试构造方法赋值
public class Test6_Constructor2 {
public static void main(String[] args) {
//自动触发无参构造
Student2 s = new Student2();
//触发含参构造,在创建对象时给成员变量赋值。
Student2 s2 = new Student2(2);
}
}
//创建Student2类
class Student2{
//成员变量
int age;
//提供构造方法
public Student2() {
System.out.println("无参构造");
}
//提供重载的构造方法
public Student2(int a) {
//a在方法里面是局部变量
//1,构造方法可以用来给变量赋值
//流程:当含参的方式创建对象时,会自动触发含参构造。把参数2给a赋值,a拿到值之后再给成员变量age赋值
age = a;
System.out.println("成员变量age:"+age);
System.out.println("含参构造");
}
}
2.1.5 概要: 属性の割り当ての順序
package com.cn.ca;
/*
* 总结:属性赋值的先后顺序
*
*
* ① 默认初始化(初始化:第一次赋值)
* ② 显式初始化
* ③ 构造器中初始化
*
* ④ 通过"对象.方法"(加了private封装控制权限了) 或 "对象.属性"的方式,赋值
*
* 以上操作的先后顺序:① - ② - ③ - ④
*
*/
public class UserTest {
public static void main(String[] args) {
User u = new User();
System.out.println(u.age);
User u1 = new User(2);
u1.setAge(3);
u1.setAge(5);
System.out.println(u1.age);
}
}
class User{
String name;//默认初始化
int age = 1;//显示初始化
public User(){
}
public User(int a){
//创建对象,属性初始化
age = a;
}
public void setAge(int a){
age = a;
}
}
2.2 JavaBean の再利用可能なコンポーネント
package com.atguigu.java1;
/*
* JavaBean是一种Java语言写成的可重用组件。
所谓JavaBean,是指符合如下标准的Java类:
>类是公共的
>有一个无参的公共的构造器
>有属性,且有对应的get、set方法
*
*/
public class Customer {
private int id;
private String name;
public Customer(){
}
public void setId(int i){
id = i;
}
public int getId(){
return id;
}
public void setName(String n){
name = n;
}
public String getName(){
return name;
}
}
2.3 コードブロックとローカルコードブロックの構築
2.3.1 コードブロックの構築
1.クラス内およびメソッド外のコード ブロック。
2. 通常、構築メソッド内の共通コードを抽出するために使用されます。オブジェクトの作成時にオブジェクトのプロパティを初期化できます。
3. 構築コード ブロックは、構築メソッドを呼び出す前に呼び出されます。
4.ロードは構築メソッドよりも優先されます。
5.オブジェクトが作成されるたびに、最初に構築コード ブロックが呼び出され、次に構築メソッドが呼び出されます。
6. 内部に出力ステートメントを含めることができます
7. クラス内に複数の非静的コード ブロックが定義されている場合、それらは宣言された順序で実行されます
8. 静的プロパティ、静的メソッド、または非静的コード ブロックは、非静的コード ブロック内で呼び出されます。プロパティ、非静的メソッド
9、{ }
テスト構築コードブロック:
package cn.tedu.block;
//1,创建对象时,会自动触发构造方法。如果有构造代码块会先执行代码块再执行构造方法88888888888888888888888888
public class Test1_Block {
public static void main(String[] args) {
//TODO 创建Person对象测试
new Person();
//2,每次创建对象都会调用构造代码块和构造方法
new Person();
new Person("name");
new Person(100);
}
}
//创建Person类
class Person{
String country;//为了让每个构造方法都使用,提高作用范围
//b,提供构造代码块 : 位置:在类里方法外
{
//3,构造代码块:用来提取构造方法的共性
country = "中国人";
}
//a,提供构造方法
public Person() {
System.out.println("无参构造...,我的国籍是:"+country);
}
//c,提供重载构造方法
public Person(String c) {
System.out.println("含参构造...,我的国籍是:"+country);
}
public Person(int a) {
System.out.println("含参构造...,我的国籍是:"+country);
}
}
2.3.2 ローカルコードブロック
1.メソッド内のコードブロック(通常のメソッド、コンストラクタメソッドの両方を使用可能)
2. 通常は変数のスコープを制御するために使用されます(括弧を削除すると無効になります)
3. 変数のスコープは小さいほど良いメンバー変数にはスレッドの安全性の問題が発生します
。メソッドが呼び出されたときにトリガーされます
5.メソッドが呼び出されるときに、ローカル コード ブロックを呼び出します。
6. { }
2.3.3 テスト: 構築、ローカル コード ブロックのロード順序
構築コードブロック→構築方法→部分コードブロック
package cn.tedu.block;
//测试代码块
//1,创建对象时,会自动触发构造方法。如果有构造代码块会先执行代码块再执行构造方法,
//若局部代码块写在构造方法里面,构造方法和局部代码块的顺序是看程序写代码的顺序执行。
//若写在普通方法里面,则是调用的时候用(它则是最后用,因为是先创建对象,在通过引用调用方法)。
//总结:
//1,构造代码块:创建对象时触发,在类里方法外,用来抽取构造方法的共性
//2,局部代码块:方法调用时触发,在方法里,用来控制变量的作用范围
//若没有创建对象,构造代码块都不会自动执行
//2.每次创建对象都会调用构造代码块和构造方法
public class Test1_Block {
public static void main(String[] args) {
//TODO 创建Person对象测试
new Person();
//2,每次创建对象都会调用构造代码块和构造方法
new Person();
new Person("name");
new Person(100).sleep();//触发局部代码块
}
}
//创建Person类
class Person{
String country;//为了让每个构造方法都使用,提高作用范围
//b,提供构造代码块 : 位置:在类里方法外
{
//3,构造代码块:用来提取构造方法的共性
country = "中国人";
}
//a,提供构造方法
public Person() {
System.out.println("无参构造...,我的国籍是:"+country);
}
//c,提供重载构造方法
public Person(String c) {
System.out.println("含参构造...,我的国籍是:"+country);
}
public Person(int a) {
System.out.println("含参构造...,我的国籍是:"+country);
}
//提供普通方法
public void sleep() {
//局部代码块: 位置:在方法里 + 作用:控制变量的作用范围
{
int i = 10;
System.out.println("局部代码块..."+i);
}
// System.out.println(i);
}
}
2.4 このキーワード
2.4.1 コンセプト
説明する:
1.これは、このクラス オブジェクトの参照オブジェクトを表します。
2.これは 2 か所でのみ使用されます。1 つは、メンバー変数の名前とローカル変数の名前が同じ場合、これを使用してメンバー変数を参照し、メンバー変数とローカル変数の違いを区別することです。変数。もう 1 つはコンストラクター間の呼び出しに使用され、別のコンストラクターは最初の行で使用されます。
知らせ:
1.メンバ変数とローカル変数の名前が異なる場合は省略可能です。
2.コンストラクターでは、this() を最初の行に配置する必要があります。
2.4.2 フォーム
name=name;
age=age;
//解释:其实是想把Student类的局部变量name的值赋值给成员变量,相当于你想操作是这样的:
Student.name=name;
//但是你不能直接写类名,这时候就用代表本类的对象this来完成。代码变成了:
this.name=name;
文法:
1)this.成员变量名-----------访问成员变量(掌握)
this.name=name;
2)this.方法名()------------调用方法(不用掌握)
因为在类中没有相同的方法,所以不用写this来区分。
3)this()------------------调用构造方法(只能重载类名相同)根据它的参数列表
(一个构造方法可以通过this关键字调用另外一个重载的构造方法)
2.4.3 演習1: 変数名が同じ場合
ローカル変数とメンバー変数が同じ名前である場合に、それらを区別するために使用されます。
近くに同じ名前の変数がある場合、その変数の近接原理に従いますが、そのメンバー変数を呼び出すにはどうすればよいでしょうか?
package cn.tedu.thisdemo;
//测试this关键字
public class Test2_This {
public static void main(String[] args) {
//创建Student对象测试
Student s = new Student();
s.show();
}
}
代码体现1:
//创建Student类
class Student{
int count ;//成员变量
int sum = 20;//成员变量
public void show() {
int sum = 10;//局部变量
System.out.println(sum);//10,就近原则
System.out.println(count);//0
// System.out.println(new Student().sum);//20
//1,this关键字代表的是本类对象的一个引用就相当于Student this = new Student();8888888888888888888
//2,当成员变量和局部变量同名时(如:sum),可以使用this来区分。this调用的是本类的成员变量。888888888888888888888888(当成员变量和局部变量名不同时可以省略this)
//(因为局部变量在方法里,想要调用先调用方法才行,所以它调用的变量是成员变量)
System.out.println(this.sum);//20
}
}
代码体现2:
class Student2{
String name;
//创建对象时,给成员变量name赋值
public Student2(String name) {
// name = name;//没有成功的给成员变量name赋值,因为等号左右两边都是局部变量 //就近原则
this.name = name;//等号左边使用的是成员变量,右边是局部变量
//注意:变量只要在方法上就是局部变量,而不是在{ }里才是。
System.out.println(name);
System.out.println(this.name);
}
}
2.4.4 演習 2: コンストラクター メソッド間の呼び出し
package cn.tedu.thisdemo;
//this在构造方法间调用
//总结:this只用在2个地方:一个是,成员变量名和局部变量名相同时,用this指代成员变量用来区分成员变量和局部变量的区别。另一个是,用来构造方法间进行调用另一个构造方法在第一行时用
//1,this可以在构造方法间互相调用
//2,如果在构造方法里出现了this关键字,必须放在第一条语句的位置
//构造方法之间不能同时相互调用,否则会出现死循环,报错。也不能自己调自己。
public class Test3_This2 {
public static void main(String[] args) {
//无参创建对象测试
Teacher t = new Teacher();
//含参创建对象测试
Teacher t2 = new Teacher("jack");
}
}
//创建Teacher类
class Teacher{
//提供构造方法
public Teacher() {
//在 无参构造 中访问 含参构造
// this("jack");
System.out.println("无参构造");
}
public Teacher(String name) {
//在 含参构造 中访问 无参构造
this();
System.out.println("含参构造"+name);
}
}
2.4.5 演習 3: 総合演習
package com.atguigu.java2;
/*
* this关键字的使用:
* 1.this可以用来修饰、调用:属性、方法、构造器
*
* 2.this修饰属性和方法:
* this理解为:当前对象 或 当前正在创建的对象
*
* 2.1 在类的方法中,我们可以使用"this.属性"或"this.方法"的方式,调用当前对象属性或方法。但是,
* 通常情况下,我们都选择省略"this."。特殊情况下,如果方法的形参和类的属性同名时,我们必须显式
* 的使用"this.变量"的方式,表明此变量是属性,而非形参。
*
* 2.2 在类的构造器中,我们可以使用"this.属性"或"this.方法"的方式,调用当前正在创建的对象属性或方法。
* 但是,通常情况下,我们都选择省略"this."。特殊情况下,如果构造器的形参和类的属性同名时,我们必须显式
* 的使用"this.变量"的方式,表明此变量是属性,而非形参。
*
* 3. this调用构造器
* ① 我们在类的构造器中,可以显式的使用"this(形参列表)"方式,调用本类中指定的其他构造器
* ② 构造器中不能通过"this(形参列表)"方式调用自己
* ③ 如果一个类中有n个构造器,则最多有 n - 1构造器中使用了"this(形参列表)"
* ④ 规定:"this(形参列表)"必须声明在当前构造器的首行
* ⑤ 构造器内部,最多只能声明一个"this(形参列表)",用来调用其他的构造器
*
*
*/
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.setAge(1);
System.out.println(p1.getAge());
p1.eat();
System.out.println();
Person p2 = new Person("Jerry",20);
System.out.println(p2.getAge());
}
}
class Person{
private String name;
private int age;
public Person(){
// this.eat();
String info = "Person初始化时,需要考虑如下的1,2,3,4...(共40行代码)";
System.out.println(info);
}
public Person(String name){
this();
this.name = name;
}
public Person(int age){
this();
this.age = age;
}
public Person(String name,int age){
this(age);
this.name = name;
//this.age = age;
//Person初始化时,需要考虑如下的1,2,3,4...(共40行代码)
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return this.age;
}
public void eat(){
System.out.println("人吃饭");
this.study();
}
public void study(){
System.out.println("人学习");
}
}
2.5 Package および import キーワードの使用
package com.atguigu.java2;
import java.lang.reflect.Field;
import java.util.*;
import com.atguigu.exer4.Account;
import com.atguigu.exer4.Bank;
import com.atguigu.java2.java3.Dog;
import static java.lang.System.*;
import static java.lang.Math.*;
/*
* 一、package关键字的使用
* 1.为了更好的实现项目中类的管理,提供包的概念
* 2.使用package声明类或接口所属的包,声明在源文件的首行(这里的首行要求不严格:指
* 的是声明的第一条语句,在它之前有换行的空格也算是首行)
* 3.包,属于标识符,遵循标识符的命名规则、规范(xxxyyyzzz)、“见名知意”
* 4.每"."一次,就代表一层文件目录。
*
* 补充:同一个包下,不能命名同名的接口、类。
* 不同的包下,可以命名同名的接口、类。
*
* 二、import关键字的使用
* import:导入
* 1. 在源文件中显式的使用import结构导入指定包下的类、接口
* 2. 声明在包的声明和类的声明之间
* 3. 如果需要导入多个结构,则并列写出即可
* 4. 可以使用"xxx.*"的方式,表示可以导入xxx包下的所有结构
* 5. 如果使用的类或接口是java.lang包下定义的,则可以省略import结构
* 6. 如果使用的类或接口是本包下定义的,则可以省略import结构
* 7. 如果在源文件中,使用了不同包下的同名的类,则必须至少有一个类需要以全类名的方式显示。
* 8. 使用"xxx.*"方式表明可以调用xxx包下的所有结构。但是如果使用的是xxx子包下的结构,则仍需要显式导入
*
* 9. import static:导入指定类或接口中的静态结构:属性或方法。
*/
public class PackageImportTest {
public static void main(String[] args) {
String info = Arrays.toString(new int[]{
1,2,3});
Bank bank = new Bank();
ArrayList list = new ArrayList();
HashMap map = new HashMap();
Scanner s = null;
System.out.println("hello!");
Person p = new Person();
Account acct = new Account(1000);
//全类名的方式显示
com.atguigu.exer3.Account acct1 = new com.atguigu.exer3.Account(1000,2000,0.0123);
Date date = new Date();
java.sql.Date date1 = new java.sql.Date(5243523532535L);
Dog dog = new Dog();
Field field = null;
out.println("hello");
long num = round(123.434);
}
}
2.6 継承
2.6.1 コンセプト
継承は、オブジェクト指向プログラミングの最も重要な機能の 1 つです。
継承とは、既存のクラスから新しいクラスを派生させることであり、新しいクラスは既存のクラスのデータ属性や動作を吸収し、新しい機能を拡張できます(クラス間)。
Javaの継承は、既存のクラスの定義をベースとして新しいクラスを作成する技術であり、新しいクラスの定義では、新しいデータや新しい関数を追加したり、親クラスの関数を使用したりできますが、選択的に継承することはできません親クラス/スーパークラス、クラス/基本クラス。(サブクラスは派生クラスとも呼ばれます)
利点: このテクノロジーにより、以前のコードを非常に簡単に再利用できるため、開発サイクルを大幅に短縮し、開発コストを削減できます。
例:
// A: 子类 C:父类
class A extends c{
//原来的eat()拿走了
}//注意:继承的语法,第二个类不需要再使用class
class B extends c{
//原来的eat()拿走了
}
class c{
public void eat(){
syso("eat");
}
}
2.6.2 特徴
- 使用伸びるキーワード
- 親クラスの機能(変数やメソッドを含む)をコピーしたサブクラスに相当します。プライベートなリソースも継承できます。ただし、カプセル化の影響でサブクラスを直接呼び出すことはできず、サブクラスを作成して変更することもできません。オブジェクト。プライベート リソースを間接的に呼び出すパブリック メソッドを通じてのみ渡すことができます。)
- サブクラス A が親クラス B を継承すると、サブクラス A は親クラス B で宣言された情報を取得します。すべてのプロパティとメソッド。特に、親クラスでプライベートとして宣言された属性またはメソッドの場合、サブクラスが親クラスを継承した後も、親クラスでプライベート構造を取得したものとみなされます。カプセル化の影響により、サブクラスは親クラスのプライベート構造体を直接呼び出すことができません。
- Java は単一継承のみをサポートします (スーパー クラスは複数の派生クラスを持つことができ、派生クラスは 1 つのスーパー クラスからのみ継承できます)。
- 相続が可能(祖父・子・孫の関係)
- サブクラスは親クラスを継承した後、直接の親クラスとすべての間接的な親クラスで宣言されたプロパティとメソッドを取得します。
- 親クラスのプライベートメンバーを継承できません
- 継承は主に機能の変更に使用され、サブクラスは親クラスの機能を継承し、同時に機能を拡張することができます。
- の関係です
- Java では、派生クラス (最初に親クラス、次に子クラス) を構築する前にスーパークラスを構築する必要があると規定しています。
- コンストラクターは継承できません。
2.6.3 オブジェクトクラスの理解
- クラスの親クラスを明示的に宣言しない場合、このクラスは java.lang.Object クラスを継承します。
- すべての Java クラス (java.lang.Object クラスを除く) は、直接的または間接的に java.lang.Object クラスを継承します。
- これは、すべての Java クラスが java.lang.Object クラスによって宣言された関数を持っていることを意味します。
- Object クラスは lang パッケージに属しているため、パッケージをインポートする必要はありません。
2.6.4 入門ケース
package cn.tedu.extendsdemo;
//测试继承的入门案例
public class Test4_Extends {
public static void main(String[] args) {
//创建父类对象测试,提高代码的复用性/高内聚,父类写子类的共性
Father f = new Father();
f.eat();
// System.out.println(f.sum);
//创建子类对象测试
Son s = new Son();
//5,子类可以使用父类的所有功能,除了private的
s.eat();
// System.out.println(s.sum);
//6,继承具有传递性,爷爷的功能,孙子类里也能用
s.game();
System.out.println(s.count);
}
}
class Yeye{
//没有指明默认继承Lang包下的Object类
int count ;
public void game() {
System.out.println("下象棋");
}
}
//创建父类
//!!耦合性 --继承就是一种强耦合性!!!程序中耦合性越低越好,降低程序的耦合性。 888888888888888888888888(后续用接口)
class Father extends Yeye{
//4,如果父类中,资源被private修饰,这个资源子类无法继承
private int sum =10;
public void eat() {
System.out.println("爸爸在吃猪肉");
}
}
//创建子类
//1,用extends关键字表示继承关系
//3,Java只支持单继承,一个子类只能继承于一个父类
class Son extends Father{
//2,继承后,子类就能使用父类的功能,就相当于子类把父类的功能复制了一份
} //继承不会改变源码,而是拓展
2.6.5 テスト: プライベート プロパティ メソッドも継承可能
package com.cn.extend;
public class Test {
public static void main(String[] args) {
Student stu = new Student();
stu.setAge(15);//吃饭
stu.eat();//睡觉
/* 说明:此时使用的对象是子类student,通过公共的方法调用私有的资源,
* 而私有资源定义在父类person中,那么此时在子类中必定继承了私有资源
* 只不过这些私有的资源由于封装性无法直接使用
*
*/
}
}
class Person {
String name;
private int age;
public void eat(){
System.out.println("吃饭");
sleep();
}
private void sleep(){
System.out.println("睡觉");
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class Student extends Person{
private String name = "小明";
}
2.6.6 メンバー変数の使用
package cn.tedu.extendsdemo;
//测试继承中成员变量的用法
//可以使用从父类中继承过来的,也可以用自己特有的
public class Test5_UseExtends {
public static void main(String[] args) {
//TODO 创建子类对象测试
Erzi zi = new Erzi();
System.out.println(zi.count);//20
System.out.println(zi.sum);
}
}
//创建父类
class BaBa{
int count = 10;
}
//创建子类
class Erzi extends BaBa{
int count = 20;
int sum = 20;
}
2.6.7 メンバーメソッドの使用
package cn.tedu.extendsdemo;
//测试继承中成员方法的用法
public class Test5_UseExtends {
public static void main(String[] args) {
//TODO 创建子类对象测试
Erzi zi = new Erzi();
//可以使用父类的功能,也可以使用自己特有的功能
System.out.println(zi.count);//20
System.out.println(zi.sum);
//2,如果子类没有发生方法重写,eat()使用父类的功能。
//如果子类发生了方法重写,使用的就是重写之后,也就是子类的eat()的功能。888888888888
zi.eat();//爸爸在吃肉 --》儿子在喝汤
zi.code();//可以使用特有的方法
}
}
//创建父类
class BaBa{
int count = 10;
public void eat() {
System.out.println("爸爸在吃肉");
}
}
//创建子类
class Erzi extends BaBa{
int count = 20;
int sum = 20;
//1,方法重写:出现的原因是:当父类的功能需要修改时,我们不能直接打开父类代码修改源码!!我可只能功能扩展
//扩展的过程:先发生继承关系,然后发生方法重写的现象。要求子类的方法声明和父类一模一样。
public void eat() {
System.out.println(count);//20
System.out.println(super.count);//10,通过super调用父类的功能
System.out.println("儿子在喝汤");
}
//提供子类特有方法
public void code() {
System.out.println("儿子在敲代码");
}
}
2.6.8 コンストラクタの利用(コンストラクタの継承は不可)
1. サブクラスがオブジェクトを作成すると、デフォルトで親クラスのパラメータなしのコンストラクターにアクセスします
2. コンストラクター メソッドの最初の行に、デフォルトのステートメント super(); があります
3. 親クラスがアクセスするときパラメーターのないコンストラクターはありません。super を使用して親クラスの他のコンストラクターを呼び出すことができます
package cn.tedu.extendsdemo;
//测试继承中构造方法的使用
public class Test6_UseExtends2 {
public static void main(String[] args) {
//TODO 创建子类对象测试
Zi zi = new Zi();
}
}
//创建父类
class Fu{
//如果父类中,只提供含参构造,这时,无参构造就会被覆盖,没了!
//建议提供一个无参构造。
public Fu(String n) {
System.out.println("Fu()...");
}
}
//创建子类
class Zi extends Fu{
public Zi() {
//0,super关键字常用于子类中,当子类要使用父类功能时,通过super代表父类对象的引用。
//1,子类创建对象时,默认就会存在super(),也就默认就会去访问父类的无参构造。
// super();//父类没有无参构造了!!
//2,当父类中不提供无参构造时,只能通过super调用父类的含参构造
//3,super关键字如果在构造方法中使用,必须是第一条语句。
super("tony");
System.out.println("Zi()...");
}
}
2.7 スーパーキーワード
注:
1. 親クラスの内容は super キーワードを通じて使用できます
2. Super は親クラスの参照オブジェクトを表します
3. コンストラクターで使用する場合は、最初のステートメントである必要があります。
文法:
1)super.成员变量名------访问超类的成员变量(用于:子父类定义同名的变量,想要在子类中使用父类的变量时使用。父子类定义2个相同名字的变量不会覆盖,变量没有覆盖功能。)
2)super.方法名()-------调用超类的方法(用于:当子类重写了父类中的方法以后,我们想在子类的方法中调用父类中被重写的方法时,则必须显式的使用"super.方法"的方式,表明调用的是父类中被重写的方法。)
3)super()--------------调用超类的构造方法
質問:サブクラスのオブジェクトをインスタンス化するときに、最初に親クラスのコンストラクターが呼び出されるのはなぜですか??
回答: サブクラスは親クラスを継承した後、親クラスのコンテンツ (プロパティ/フィールド) を取得し、これらのコンテンツは使用前に初期化する必要があるため、最初に親クラスのコンストラクターを呼び出してコンテンツを初期化する必要があります。
知らせ:
- super はサブクラスのメソッドまたはコンストラクター内でのみ使用できます。
- サブクラス コンストラクター内に存在できるスーパーは 1 つだけです。
- super がサブクラスのコンストラクター内で親クラスのコンストラクターを呼び出す場合、それはサブクラスのコンストラクターの最初の行に配置される必要があります。(通常の方法ではそのような必要はありません)
- 記述しなくても、デフォルトでは、サブクラスのコンストラクターの最初の行で、親クラスのパラメーターなしのコンストラクターが呼び出されます。親クラスがクラス コンストラクターをオーバーロードする場合は、渡されたさまざまなパラメーターに従ってそのサブクラス スーパーを呼び出す必要があります。
- サブクラスのコンストラクターでは、親クラスのコンストラクターを呼び出すことも、親クラスの通常のメソッドを呼び出すこともできます。サブクラスの通常のメソッドは、親クラスの通常のメソッドのみを呼び出すことができますが、コンストラクター メソッドを呼び出すことはできません。
2.7.1 サブクラスオブジェクトのインスタンス化の全プロセス
サブクラス オブジェクトのインスタンス化のプロセス全体:
-
結果から判断すると:(継承)
サブクラスは親クラスを継承した後、親クラスで宣言された属性やメソッドを取得します。
サブクラスのオブジェクトが作成されると、親クラスで宣言されたすべての属性がヒープ領域にロードされます。 -
プロセスの観点から見ると、
サブクラスのコンストラクターを通じてサブクラス オブジェクトを作成するときは、間違いなくその親クラスのコンストラクターを直接的または間接的に呼び出し、次に親クラスの親クラスのコンストラクターを呼び出します。
.lang.Object クラスの空のパラメーターを持つコンストラクターが呼び出されるまで。親クラスのすべての構造体がロードされているからこそ、メモリ内に親クラスの構造体が存在することがわかり、その場合にのみサブクラス オブジェクトの呼び出しを検討できます。
明確さ: サブクラス オブジェクトを作成するときに親クラスのコンストラクターが呼び出されますが、オブジェクトは最初から最後まで作成されており、それが新しいサブクラス オブジェクトです。
2.8 これとスーパーの違い
表現されるオブジェクトが異なります:
- this: このクラスのオブジェクトへの参照を表します。
- super: 親クラス オブジェクトへの参照を表します。
前提:
3. this: 継承せずに使用できます。
4. super: 継承条件下でのみ使用できます。
コンストラクターを呼び出すとき:
5. this: このクラスの構造
6. super: 親クラスの構造
注: this と super は同じコンストラクター内に同時に出現することはできません。出現する限り、コンストラクターの最初の行に配置する必要があります。同時に出現する場合、どちらを最初に配置する必要がありますかライン?
2.9 メソッドの書き換え
前提条件:親子クラスで発生。
同じものが 2 つ、小さいものが 2 つ、大きいものが 1 つという原則に従います。
两同:方法名相同,参数列表相同(注意:参数列表的相同不相同只和形参类型有关,和形参名字没有关系。)
两小:
1: 子类的返回值类型小于或等于父类的
1.1void和基本类型时,必须相同
1.2引用类型时:小于或等于父类的
2:子类抛出的异常小于或等于父类的
一大:子类的访问权限大于或等于父类的
注:
- オーバーライドとはメソッドの書き換えを指し、属性にはオーバーライド機能はありません (過積載も)。
- オーバーライドされたメソッド本体も同じにすることができます。これはオーバーロードに似ていますが意味がなく、一般に異なります。
- プライベート メソッドは継承できないため、親クラスのプライベート メソッドをオーバーライドすることはできません。
- 静的メソッドはオーバーライドできず、クラスに属し、インスタンスには属しません。
- サブクラスと親クラスで同じ名前とパラメータを持つメソッドは、非静的として宣言するか (オーバーライドを考慮)、両方とも静的として宣言する (オーバーライドしない) 必要があります。
- 最終的に変更されたメソッドはオーバーライドできません。
- コンストラクターをオーバーライドすることはできません。
- オーバーライドされたメソッドには @Override アノテーションが付けられます。このメソッドには特定の小さな関数があり、このメソッドが親クラスの関数をオーバーライドすることを示します。
なぜ書き換えるのか?? ?
親クラスの機能がサブクラスで必要ない場合や必ずしも満たさない場合には、書き換える必要があります。。
2.9.1 入門ケースの書き換え
package cn.tedu.extendsdemo;
//测试继承中成员方法的用法
public class Test5_UseExtends {
public static void main(String[] args) {
//TODO 创建子类对象测试
Erzi zi = new Erzi();
//可以使用父类的功能,也可以使用自己特有的功能
System.out.println(zi.count);//20
System.out.println(zi.sum);
//2,如果子类没有发生方法重写,eat()使用父类的功能。
//如果子类发生了方法重写,使用的就是重写之后,也就是子类的eat()的功能。888888888888
zi.eat();//爸爸在吃肉 --》儿子在喝汤
zi.code();//可以使用特有的方法
}
}
//创建父类
class BaBa{
int count = 10;
public void eat() {
System.out.println("爸爸在吃肉");
}
}
//创建子类
class Erzi extends BaBa{
int count = 20;
int sum = 20;
//1,方法重写:出现的原因是:当父类的功能需要修改时,我们不能直接打开父类代码修改源码!!我可只能功能扩展
//扩展的过程:先发生继承关系,然后发生方法重写的现象。要求子类的方法声明和父类一模一样。
public void eat() {
System.out.println(count);//20
System.out.println(super.count);//10,通过super调用父类的功能
System.out.println("儿子在喝汤");
}
//提供子类特有方法
public void code() {
System.out.println("儿子在敲代码");
}
}
2.10 拡張
2.10.1 書き換えとオーバーロードの違い(オーバーロードとオーバーライドの違い)
1. オーバーロード: 同じクラス内の複数のメソッドが同じ名前を持つが、これらのメソッドのパラメーター リストが異なることを意味します。つまり、パラメーターの数やパラメーターの型がまったく同じであることはできません。中間
的に、サブクラスによって定義されたメソッドは、親クラスのメソッドと同じメソッド名、同じパラメータ リスト、および同じ戻り値の型を持ちます。3. 書き換えは、親クラスとサブクラス間のポリモーフィズムの現れで
す
。 4. オーバーロードはクラスのポリモーフィズムの現れです
2.10.2 継承されたメモリ構造
3 Day08 – オブジェクト指向 3
3.1 静的
3.1.1 コンセプト
1. Java のキーワードです2.メンバー(メンバー変数やメンバーメソッド、静的コードブロック)
を変更するために使用されますが、ローカルリソースやコンストラクターは変更できません。
3.1.2 特徴
1. メンバー変数、メンバーメソッド、および静的コードブロックを変更できます。静的内部クラスを除き、クラスは変更できません。
2.オブジェクトのロード前に、クラスがロードされるときにロードさ
れます。 3. 一度だけロードされると、常に存在し、新しいスペースは開かれません。
4. グローバルに一意で、グローバルに共有さ
れます。 5. クラス名によって直接呼び出すことができます (静的リソースは使用されます) クラス名を通じて呼び出されます ポイント)
6.静的メソッドはオーバーライドできません。
注:静态属性、静态方法和私有的属性都可以被继承和隐藏而不能被重写,因此不能实现多态,不能实现父类的引用可以指向不同子类的对象。非静态方法可以被继承和重写,因此可以实现多态。静态方法和属性是属于类的,调用的时候直接通过类名.方法名完成调用,不需要继承即可调用 。
質問: 静的は静的のみを呼び出すことができ、非静的は静的と非静的の両方を呼び出すことができます。なぜですか?
静的リソースはクラスのロード時にロードされ、オブジェクトのロードよりも優先されるため、クラスのロードが完了した時点ではオブジェクトが作成されていないため、呼び出すことができません。
同様に、 static は this や super と共有することはできません: this や super はオブジェクトを置き換えます. static がある場合、オブジェクトが存在しない可能性があります. main メソッドも static メソッドであるため、this と super は記述されません。
呼び出し関係の概要:
同じクラス間の呼び出しではオブジェクトを作成する必要はありませんが、異なるクラス間のリソース呼び出しではオブジェクトが作成されるか、静的リソースが使用されます。
非静的リソース(インスタンス変数と通常のメソッド (ローカル変数を除く)。ローカル変数を呼び出す場合は、最初にメソッドを呼び出す必要があるためです。) は、オブジェクト、静的リソース(静的変数と静的メソッド) は、オブジェクトを作成するか、クラス名を直接呼び出すことによって作成できます (静的リソースを呼び出すにはクラス名を使用することをお勧めします。)。
3.1.3 入門ケース
package cn.tedu.staticdemo;
//static一般放在返回值类型之前。
//这个类用来测试静态入门案例
public class Test1_Static {
public static void main(String[] args) {
//2,静态资源优先于对象加载,会优先加载进内存
//静态资源访问:有2种。
//1:通过new对象进行访问·(但是不推荐用)
//2:直接通过类名.访问
//非静态资源只能有一种:通过对象
Person.game();
System.out.println(Person.age);
//TODO 创建Person对象测试
Person p = new Person();
p.eat();
System.out.println(p.name);
//1.1, 静态资源,可以通过对象访问
p.game();
System.out.println(p.age);
//1, 静态资源,还可以通过类名访问
Person.game();
System.out.println(Person.age);
//3,静态资源,在多个对象间,是共享的
Person p1 = new Person();
Person p2 = new Person();
p1.age=10;
System.out.println(p2.age);//10
}
}
//创建Person类
class Person{
//普通资源
String name;
public void eat() {
System.out.println("eat()...");
}
//静态资源 -- 使用static修饰
static int age;
static public void game () {
System.out.println("game()...");
}
}
3.1.4 包括的なケース
package com.atguigu.java1;
/*
* static关键字的使用
*
* 1.static:静态的
* 2.static可以用来修饰:属性、方法、代码块、内部类
*
* 3.使用static修饰属性:静态变量(或类变量)
* 3.1 属性,按是否使用static修饰,又分为:静态属性 vs 非静态属性(实例变量)
* 实例变量:我们创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性。当修改其中一个对象中的
* 非静态属性时,不会导致其他对象中同样的属性值的修改。
* 静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致
* 其他对象调用此静态变量时,是修改过了的。
* 3.2 static修饰属性的其他说明:
* ① 静态变量随着类的加载而加载。可以通过"类.静态变量"的方式进行调用
* ② 静态变量的加载要早于对象的创建。
* ③ 由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中。
*
* ④ 类变量 实例变量
* 类 yes no
* 对象 yes yes
*
* 3.3 静态属性举例:System.out; Math.PI;
*
* 4.使用static修饰方法:静态方法
* ① 随着类的加载而加载,可以通过"类.静态方法"的方式进行调用
* ② 静态方法 非静态方法
* 类 yes no
* 对象 yes yes
* ③ 静态方法中,只能调用静态的方法或属性
* 非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性
*
* 5. static注意点:
* 5.1 在静态的方法内,不能使用this关键字、super关键字
* 5.2 关于静态属性和静态方法的使用,大家都从生命周期的角度去理解。
*
* 6. 开发中,如何确定一个属性是否要声明为static的?
* > 属性是可以被多个对象所共享的,不会随着对象的不同而不同的。
* > 类中的常量也常常声明为static
*
* 开发中,如何确定一个方法是否要声明为static的?
* > 操作静态属性的方法,通常设置为static的
* > 工具类中的方法,习惯上声明为static的。 比如:Math、Arrays、Collections
*/
public class StaticTest {
public static void main(String[] args) {
Chinese.nation = "中国";
Chinese c1 = new Chinese();
c1.name = "姚明";
c1.age = 40;
c1.nation = "CHN";
Chinese c2 = new Chinese();
c2.name = "马龙";
c2.age = 30;
c2.nation = "CHINA";
System.out.println(c1.nation);
//编译不通过
// Chinese.name = "张继科";
c1.eat();
Chinese.show();
//编译不通过
// Chinese.eat();
// Chinese.info();
}
}
//中国人
class Chinese{
String name;
int age;
static String nation;
public void eat(){
System.out.println("中国人吃中餐");
//调用非静态结构
this.info();
System.out.println("name :" +name);
//调用静态结构
walk();
System.out.println("nation : " + nation);
}
public static void show(){
System.out.println("我是一个中国人!");
//不能调用非静态的结构
// eat();
// name = "Tom";
//可以调用静态的结构
System.out.println(Chinese.nation);
walk();
}
public void info(){
System.out.println("name :" + name +",age : " + age);
}
public static void walk(){
}
}
3.1.5 静的メソッドのメモリマップ
メモリ: JVM によって管理されます。
1. ヒープ: すべての新しいオブジェクト (新しいオブジェクトとメンバー変数を含む)
2. スタック: ローカル変数 (メソッド パラメーターの基本型の数値参照型のアドレスを含む)
3. メソッド領域: 。クラスバイトコードファイル、静的メソッド領域、定数プール。
3.2 静的コードブロック
3.2.1 概要
1. 静的コード ブロック: クラスがロードされるときにロードされ、ロードされるだけです (移行) 1 回。通常はプロジェクトの初期化に使用されます。
2.場所: クラス内のメソッドの外
3.2.2 特徴
- 内部に出力ステートメントを含めることができます
- クラスがロードされるときに実行され、1 回だけ実行されます
- 機能: クラス情報の初期化
- クラス内に複数の静的コード ブロックが定義されている場合、それらは宣言された順序で実行されます。
- 静的コード ブロックの実行は、非静的コード ブロックの実行より優先されます。
- 静的コード ブロック内では静的プロパティと静的メソッドのみを呼び出すことができ、非静的構造体を呼び出すことはできません。
構文:
static{
…
}
3.2.3 静的、構造的、およびローカル コード ブロックの読み込み順序をテストする
実行順序は、:静的コード ブロックはクラスのロード時に自動的に呼び出され、1 回だけ呼び出されるため最も高速で、次に構築コード ブロック、構築メソッド、ローカル コードが続きます。
package cn.tedu.block;
//测试代码块
//总结:
//1, 触发时间节点:调用方法时,会先进入类里面,然后会自动调用静态块(即,类被第一次加载时)
//2,位置 :类里面,方法外
//3,作用/功能:只被加载一次的时候用。
//执行顺序是:静态代码块最快,因为它是类加载的时候被自动调用,且只调用一次其次是构造代码块,构造方法,局部代码快。
public class Test3_Block {
public static void main(String[] args) {
//TODO 创建对象测试
TestBlock tb = new TestBlock();
tb.show();//触发局部代码块
TestBlock tb2 = new TestBlock();
}
}
//创建TestBlock类
class TestBlock{
//1,提供构造代码块
{
System.out.println("构造代码块");
}
//2,提供静态代码块:加载的早,而且只加载一次
static{
System.out.println("静态代码块");
}
//3,提供构造方法
public TestBlock() {
System.out.println("构造方法");
}
//4,提供局部代码块
public void show() {
{
System.out.println("局部代码块");
}
}
}
3.2.4 概要: 静的コード ブロック、構築されたコード ブロック、ローカル コード ブロック
静的コード ブロックstatic{ }: クラスのロード時にロードされ、一度だけロードされます。通常、プロジェクトの初期化に使用されます。クラス内のメソッドの外側。
構築コード ブロック{ }: オブジェクトの作成時に自動的に呼び出されます。オブジェクトが作成されるたびに呼び出されます。通常、構築メソッドで共通コードを抽出するために使用されます。オブジェクトのプロパティを初期化できます。オブジェクトを作成しています。クラス内のメソッドの外側。
ローカル コード ブロック{ }: メソッド呼び出し時に呼び出され、変数のスコープを制御するために使用されます。メソッド内。
3.2.5 拡張: 静的コード ブロックと静的メソッドの違い
- プロジェクトの開始時に一部のコードを実行する必要がある場合は、アクティブに実行される静的コード ブロックを使用する必要があります。
- プロジェクトの開始時にオブジェクトを作成せずに初期化する必要がある場合は、他のプログラムから呼び出されたときに静的メソッドを使用する必要があり、この種のコードは受動的に実行されます。静的メソッドはクラスのロード時にロードされ、クラス名を使用して直接呼び出すことができます。例: main メソッドは静的である必要があり、これはプログラムのエントリ ポイントです。
2 つの違い:静的コード ブロックは自動的に実行され、静的メソッドは呼び出されると実行されます。
3.2.6 メンバ変数の代入に関する最終章
package com.atguigu.java3;
/*
* 对属性可以赋值的位置:
* ①默认初始化
* ②显式初始化/⑤在代码块中赋值(② ⑤谁在前谁在后,和定义的顺序有关)
* ③构造器中初始化
* ④有了对象以后,可以通过"对象.属性"或"对象.方法"的方式,进行赋值
*
*
* 执行的先后顺序:① - ② / ⑤ - ③ - ④
*/
public class OrderTest {
public static void main(String[] args) {
Order order = new Order();
System.out.println(order.orderId);
}
}
class Order{
int orderId = 3;
{
orderId = 4; //最终输出为4
}
//还可以写成:相当于定义了2个变量顺序无所谓
{
orderId = 4;
}
int orderId = 3;//输出为3
}
3.3 決勝
3.3.1 コンセプト
- はJavaによって提供されるキーワードです。
- ファイナルは最終という意味です。
- Final はクラス、メソッド、変数、メンバーローカルを変更できます。
本来の意図は次のような理由からです。Java で継承が発生すると、サブクラスは親クラスの機能を変更できるようになります。親クラスの機能によってサブクラスの変更が許可されない場合は、final キーワードを使用して親クラスを変更できます。。
3.3.2 特徴
-
Final によって変更されたクラスは継承できません (利点: クラスを継承不可にすることの重要性は、クラスが継承によって変更されるのを防ぎ、継承の悪用によってシステムに生じる害を制御できることです)。例: String クラス、System クラス、StringBuffer クラス。
-
Final によって変更されたメソッドをオーバーライドすることはできませんが、オーバーロードすることはできます。例: getClass(); オブジェクト クラス;
-
Final によって変更された変数は定数であり、その値は変更できません。
最終的に変更された属性 (メンバー変数) : 代入の対象となる場所は、明示的な初期化、コード ブロックでの初期化、コンストラクターでの初期化です (コンストラクター メソッドが実行されるまでオブジェクトは表示されないため、共通オブジェクトを介して代入を行うことはできません)実行するとヒープに格納されます(デフォルトで初期化された値がすでに存在します。このとき、値を代入することは定数を変更することと同等であり、定数を変更することはできません)Final 変更されたローカル変数: 特に、final が仮パラメータを変更するために使用される場合、それは仮パラメータが定数であることを示します。このメソッドを呼び出すときは、実パラメータを定数パラメータに割り当てます。この仮パラメータは、一度割り当てられるとメソッド本体内でのみ使用できますが、再割り当てすることはできません。
注: Final が参照型変数を変更する場合、参照は変更できませんが、オブジェクトのプロパティは自由に変更できることを意味します。
定数の定義形式: final 数据类型 常量名 = 值;
。通常、外部呼び出しを容易にするために、定数は static によって変更され、クラス名によって直接アクセスできます。最終的な形式はグローバル定数:ですstatic final 数据类型 常量名 = 值;
。
定数の命名規則:定数名のすべての文字を大文字にし、複数の単語をアンダースコア (「_」) で区切ることをお勧めします (推奨ですが必須ではありません)。
定数に関する注意:
- 同時に初期化するように宣言する必要があります (初期値は直接割り当てる必要があり、変更できません) (静的ブロックでの代入も可能ですが、推奨されません)
- クラス名ポイントによってアクセスされ、変更できません
定数の利点: コンパイル時に定数が特定の値に直接置き換えられる - 高効率
定数はいつ使用されますか? データは決して変更されず、頻繁に使用されます。
3.3.3 入門ケース
package com.atguigu.java3;
/*
* final:最终的
*
* 1. final可以用来修饰的结构:类、方法、变量
*
* 2. final 用来修饰一个类:此类不能被其他类所继承。
* 比如:String类、System类、StringBuffer类
*
* 3. final 用来修饰方法:表明此方法不可以被重写
* 比如:Object类中getClass();
*
* 4. final 用来修饰变量:此时的"变量"就称为是一个常量
* 4.1 final修饰属性:可以考虑赋值的位置有:显式初始化、代码块中初始化、构造器中初始化
* 4.2 final修饰局部变量:
* 尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦赋值
* 以后,就只能在方法体内使用此形参,但不能进行重新赋值。
*
* static final 用来修饰属性:全局常量
*/
public class FinalTest {
final int WIDTH = 0;
final int LEFT;
final int RIGHT;
// final int DOWN;
{
LEFT = 1;
}
public FinalTest(){
RIGHT = 2;//多个构造器都要赋值否则报错
}
public FinalTest(int n){
RIGHT = n;
}
// public void setDown(int down){
// this.DOWN = down;
// }
public void doWidth(){
// width = 20;
}
public void show(){
final int NUM = 10;//常量
// NUM += 20;
}
public void show(final int num){
// num = 20;//编译不通过
System.out.println(num);
}
public static void main(String[] args) {
int num = 10;
num = num + 5;
FinalTest test = new FinalTest();
// test.setDown(3);
test.show(10);
}
}
final class FinalA{
}
//class B extends FinalA{
//
//}
//class C extends String{
//
//}
class AA{
public final void show(){
}
}
class BB extends AA{
// public void show(){
//
// }
}
3.4 ポリモーフィズム
3.4.1 コンセプト
多態性とは、同じエンティティが同時に複数の形式を持つことを指します。これはオブジェクト指向プログラミング (OOP) の重要な機能です。これは主に、同じオブジェクトが異なる時点で異なるオブジェクトを表すことを指し、オブジェクトの複数の形式を指します。
オブジェクトの多態性: 親クラスの参照は、子クラスのオブジェクト (または親クラスに割り当てられた子クラス オブジェクトの参照) を指します。
例 1:
// 可以指向不同的子类对象,体现多态性
Animal a = new Dog();
//父类 子类
Animal a = new Cat();
例 2:
水は、水蒸気、氷、水など、さまざまな時点で複数の形態をとることがあります。
Java はどのようにしてポリモーフィズムを実現するのでしょうか? 犬には犬と小動物の2つの形態があります
class Animal {
public void eat(){
}
}
class Dog extends Animal{
}
class Test1{
main(){
//创建子类对象测
Dog d = new Dog();//小狗就是小狗
//创建多态对象测试
Animal a = new Dog();//小狗是小动物(是父类类型就是多态)
//父类引用 ,指向 子类对象
//编译ctrl+s看左边,运行ctrl+f11看右边
}
}
3.4.2 特徴
1.ポリモーフィズムの前提 1 : 2 つのクラスには継承関係がある
2.ポリモーフィズムの前提 2 : メソッドのオーバーライドが存在する必要がある
3. ポリモーフィズムとはメソッドのポリモーフィズムを指し、属性にポリモーフィズムはありません (属性のオーバーライドがないため) )書きます)。
4. 属性: 親クラスの属性が呼び出されます。
5. メソッド: 親クラスのメソッド ステートメントが呼び出され、出力は親クラスのメソッドをオーバーライドするサブクラスのメソッド本体です (静的メソッドを除く)。 6. 静的メソッド: 継承および非表示は可能ですが、オーバーライドはできません
。したがって、複数のメソッド状態を実装することはできません。
7. 親クラス参照は、次のようなサブクラス オブジェクトを指します: Animal a = new Dog(); -大きい型から小さい型へ、上向き変換とも呼ばれます
。呼び出せるものは常に等号の左側に関係しており、右側とは関係ありません。
9. ポリモーフィズムでは、コンパイルについては左側を見て (呼び出せるものについては左側
を見てください)、操作については右側を見てください(出力できるものについては右側を見てください)。は .java ソース ファイルです。Ctrl + s を押すと、.java ファイルが .class バイトコード ファイルに自動的にコンパイルされます。
3.4.3 入門ケース
package cn.tedu.duotai;
//测试多态的入门案例
public class Test5_Duotai {
public static void main(String[] args) {
//TODO 创建父类对象测试
Animal a = new Animal();
a.eat();//就是使用父类自己的功能
//TODO 创建子类对象测试
Dog d = new Dog();
d.eat();//重写前,用父类的。重写后,执行的就是子类的。
//TODO 创建多态对象测试
Animal an = new Dog();//口诀1:父类引用 指向 子类对象
//口诀2:编译看左边,运行看右边
//编译看左边:想要能够保存成功,只能使用左边也就是父类提供的方法声明部分
//运行看右边:是指发生了重写后,执行结果以子类为准
an.eat();//调用了父类的方法声明,输出的是子类的重写父类方法的方法体。 888888888888888
//多态主要用来统一调用标准:所有方法的调用向父类看齐
}
}
//1, 多态的前提:继承+重写
//创建父类
class Animal{
public void eat() {
System.out.println("爸爸在吃肉");
}
}
//创建子类
class Dog extends Animal{
@Override //它会检查是否写了方法重写,2者一块出现
public void eat() {
System.out.println("儿子在喝汤");
}
//子类特有方法,多态对象不能调用!!!!想用,可以创建子类对象用
public void eat2() {
System.out.println("儿子在喝汤");
}
}
3.5 ポリモーフィズムの利点
- ポリモーフィズムを使用すると、サブクラス オブジェクトの特定の型を気にせずに、サブクラス オブジェクトの特定のメソッドを使用したり、それを受け取るために親クラスを使用したりすることができます。このようにして、ユニバーサル コードを記述し、ユニバーサル プログラミングを行うことができます。(今すぐ:呼び出し標準を統一し、その標準が親クラスになります。)
- プログラムの拡張性と保守性の向上
3.5.1 テスト: ポリモーフィズムの利点
package com.cn.extend;
import java.sql.Connection;
//多态性的使用举例一:
public class AnimalTest {
public static void main(String[] args) {
AnimalTest test = new AnimalTest();
test.func(new Dog());
test.func(new Cat());
}
/* 情景:想要使用子类特有的方法。
* 有多态 :只需要定义一个方法,方法的参数是父类对象类型,调用时传递不同的子类对象来调用不同子类特有方法。
* 没有多态:需要定义多个重载的方法,每个方法定义对应的子类对象类型,调用时传递不同的子类对象来调用不同子类特有方法。
*/
public void func(Animal animal){
//Animal animal = new Dog(); 有多态
animal.eat();
animal.shout();
if(animal instanceof Dog){
Dog d = (Dog)animal;
d.watchDoor();
}
}
// public void func(Dog dog){ 没有多态每次需要定义重载的方法 Dog dog = new Dog();
// dog.eat();
// dog.shout();
// }
// public void func(Cat cat){ Cat cat = new Cat();
// cat.eat();
// cat.shout();
// }
}
class Animal{
public void eat(){
System.out.println("动物:进食");
}
public void shout(){
System.out.println("动物:叫");
}
}
class Dog extends Animal{
public void eat(){
System.out.println("狗吃骨头");
}
public void shout(){
System.out.println("汪!汪!汪!");
}
public void watchDoor(){
System.out.println("看门");
}
}
class Cat extends Animal{
public void eat(){
System.out.println("猫吃鱼");
}
public void shout(){
System.out.println("喵!喵!喵!");
}
}
//举例二:
class Order{
public void method(Object obj){
//只需要声明一个方法接收它的本身或子类对象类型。
}
}
//举例三:
class Driver{
/* conn = new MySQlConnection(); conn = new OracleConnection();
* 比如Connection是操作数据库连接对象Api的统一父类对象类型,通过父类的引用调用方法操作数据库
* 的步骤是固定的几步都是调用这几个方法。
* 现在连接的是mysql只需要调用方法时传递mysql的连接对象,
* 变为连接的是oracle数据库的对象,只需要在调用方法时传递oracle的对象即可,
* 连方法中的代码都不用改变(因为多态调用的是父类方法的声明,输出的是子类重写父类方法的方法体)。
*
*/
public void doData(Connection conn){
//规范的步骤去操作数据
// conn.method1();
// conn.method2();
// conn.method3();
}
}
3.6 型変換(上向き整形/下向き整形)
説明:
- このようなオブジェクトを指す親クラスへの参照のみにすることができます。
- 上向きスタイル: 自動変換
- ダウンキャスト: 強制転送が必要です (ほとんど使用されません)。通常、ポリモーフィズムでサブクラス固有のリソースを使用するために使用されます。
- Java では、スーパークラスは大きく、派生クラスは小さいとみなされます。
- Java の基本型の強制変換ではエラーは報告されませんが、成功する参照型変換は 2 種類のみです。
- サブクラスが親クラスに変換されると、元のメソッドの一部が失われる可能性があります。
強制的な型変換 (下方キャスト) の場合、成功の条件は次の 2 つだけです。
- 参照が指すオブジェクトは型です (参照が指すオブジェクトは、下向きキャストの括弧内のオブジェクトと比較して、上向きキャストでは参照が指すオブジェクトを指します)。
- 参照が指すオブジェクトはインターフェイスを実装するか、クラスを継承します。
提案: 強制変換時に上記の条件が満たされない場合、ClassCastException 型変換例外が発生します。通常、強制転送の前に、instanceof (結果は true または false) を使用して、参照が指すオブジェクトがこの型であるかどうかを判断します。
3.6.1 下向きのスタイル: のインスタンス
機能: このオブジェクトがこの特定のクラスまたはそのサブクラスのインスタンスであるかどうかを判断します。
例1:
package com.shuai;
public class Demo04 {
public static void main(String[] args) {
//类型之间的转换:类似于基本类型转换 父(高) 子(低)
//高 低
Person1 person1 = new Student1();//向上造型
//person1.go();报错,父类里面没有子类特有的方法,无法调用
//解决:将person1转化为Student1类型,就可以使用了
Student1 ss = (Student1) person1; //向下造型:想用子类特有的方法。
ss.go();
//2句话写成一块:((Student1) person1).go(); 需要多写个括号
}
}
class Person1{
public void run(){
System.out.println("输出run方法");
}
}
class Student1 extends Person1{
public void go(){
System.out.println("输出go方法");
}
}
例 2:
package com.cn.ins;
import java.util.Date;
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.eat();//创建父类对象,调用父类的方法
Man man = new Man();
man.eat(); //创建子类对象,调用子类的方法
man.age = 25;
man.earnMoney();
Person p2 = new Man();
p2.eat(); //多态,属性没有多态调用都是父类,方法调用的是父类方法声明以及子类对应的方法体。
p2.walk();
//不能调用子类所特有的方法、属性:编译时,p2是Person类型。(多态也只是调用重写后的方法,不是特有的方法)
p2.name = "Tom";
// p2.earnMoney();
// p2.isSmoking = true;
//有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致
//编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。
//如何才能调用子类特有的属性和方法?
/* 1.向下转型:使用强制类型转换符。
* 2.直接创建子类的对象进行调用
*/
Man m1 = (Man)p2;
m1.earnMoney();
m1.isSmoking = true;
//使用强转时,可能出现ClassCastException的异常。
// Woman w1 = (Woman)p2;
// w1.goShopping();
/*
* instanceof关键字的使用
*
* 引用实例 类型
* a instanceof A:判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false。
*
*
* 使用情境:为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先
* 进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型。
*
* 如果 a instanceof A返回true,则 a instanceof B也返回true.
* 其中,类B是类A的父类。(a A同一个字母表示是同一个变量类型是他本身的实例,字母B不同为true一定为父类。
* 即本身赋值给P2的值就是Man类型)
*/
if(p2 instanceof Woman){
Woman w1 = (Woman)p2;
w1.goShopping();
System.out.println("******Woman******");
}
if(p2 instanceof Man){
//由Person p2 = new Man();可以看出P2是Man类型类型对象的一个实例
Man m2 = (Man)p2;
m2.earnMoney();
System.out.println("******Man******");
}
if(p2 instanceof Person){
//是它父类的子类实例也可以
System.out.println("******Person******");
}
if(p2 instanceof Object){
System.out.println("******Object******");
}
// if(p2 instanceof String){
//
// }
//练习:
//问题一:编译时通过,运行时不通过
//举例一:
// Person p3 = new Woman();
// Man m3 = (Man)p3;
//举例二:
// Person p4 = new Person();
// Man m4 = (Man)p4;
//问题二:编译通过,运行时也通过
// Object obj = new Woman();
// Person p = (Person)obj;
//问题三:编译不通过
// Man m5 = new Woman();
// String str = new Date();
// Object o = new Date();
// String str1 = (String)o;
}
}
//class Order{
//
//}
class Person {
String name;
int age;
int id = 1001;
public void eat(){
System.out.println("人:吃饭");
}
public void walk(){
System.out.println("人:走路");
}
}
class Man extends Person{
boolean isSmoking;
int id = 1002;
public void earnMoney(){
System.out.println("男人负责挣钱养家");
}
public void eat(){
System.out.println("男人多吃肉,长肌肉");
}
public void walk(){
System.out.println("男人霸气的走路");
}
}
class Woman extends Person{
boolean isBeauty;
public void goShopping(){
System.out.println("女人喜欢购物");
}
public void eat(){
System.out.println("女人少吃,为了减肥");
}
public void walk(){
System.out.println("女人窈窕的走路");
}
}
3.7 mainメソッドの使用法
3.7.1 ケース 1: main メソッドの機能をテストする
package com.atguigu.java2;
/*
* main()方法的使用说明:
* 1. main()方法作为程序的入口
* 2. main()方法也是一个普通的静态方法
* 3. main()方法可以作为我们与控制台交互的方式。(之前:使用Scanner)
*
*
*
*/
public class MainTest {
public static void main(String[] args) {
//入口
Main.main(new String[100]);
MainTest test = new MainTest();
test.show();
}
public void show(){
}
}
class Main{
public static void main(String[] args) {
for(int i = 0;i < args.length;i++){
args[i] = "args_" + i;
System.out.println(args[i]);
}
}
}
3.7.2 ケース 2: コンソールとの対話
Eclipse の場合:
1. まず main メソッドを実行してバイトコード ファイルを生成します。
2. [Run Configurations] を選択します
。 3. 実行したばかりのプログラムがこの時点で自動的に検索されます。
4. パラメータを追加します。
5. 実行結果が
Dos コマンド ウィンドウに表示されます。
1. .java ファイルをコピーし、コード内のパッケージ名を削除します。 -> ディスク ディレクトリに配置します。
2. コマンド ライン ウィンドウを開きます
。 3. 実行するパラメータを入力します。
3.8 拡張
3.8.1 静的変数とインスタンス変数の違い
構文定義の違い: static キーワードは、インスタンス変数の前ではなく、静的変数の前に追加する必要があります。
プログラム実行時の違い: インスタンス変数はオブジェクトの属性に属し、そのインスタンス変数に領域が割り当てられ、このインスタンス変数が使用できるようになる前に、インスタンス オブジェクトを作成する必要があります。静的変数はインスタンス オブジェクトではなくクラスに属しているため、クラス変数とも呼ばれます。プログラムがインスタンス オブジェクトを作成せずにクラスのバイトコードをロードする限り、静的変数にはスペースが割り当てられ、静的変数を使用することもできますが、もちろんオブジェクトを通じて使用することもできます。
要するに、インスタンス変数はオブジェクトを作成することによってのみ使用する必要があります。静的変数はオブジェクトを作成することによって直接呼び出すことも、クラス名によって呼び出すこともできます (静的変数はクラス名によって呼び出すことを推奨します)。
4 Day09 – オブジェクト指向 4
4.1 アクセス制御文字
类
、または、のアクセス範囲を制御するために使用されます类中的成员变量
。方法
( 不能用于局部变量
)
修飾子 | 親切 | バッグ | 同じパッケージ/異なるパッケージのサブカテゴリ | 同じプロジェクト内のどこでも |
---|---|---|---|---|
公共 | √ | √ | √ | √ |
保護された | √ | √ | √ | |
デフォルト | √ | √ | ||
プライベート | √ | |||
説明: |
- public: public、同じプロジェクト内のどこでも、任意のクラス内
- protected: protected、このクラス、同じパッケージ クラス、同じパッケージ サブクラス/異なるパッケージ サブクラス。異なるパッケージはサブクラス内でのみ使用でき、同じパッケージ内であれば同じパッケージを使用できることに注意してください。
- デフォルト: このクラス、同じパッケージクラス (同じパッケージ内のクラス) には何も書きませんが、デフォルトを書くことはできません
- プライベート: プライベート、このクラス
知らせ:
- public、protected、default、private、static、final、abstract などの修飾子は、順序を区別しません。たとえば、変更されたメソッドは戻り値の型である必要があるだけです。
- クラスのアクセス修飾子は
默认的
or のみです是public
(.java ファイル内に存在できるパブリック変更クラスは 1 つだけであり、クラス名はファイル名と同じです)。 - クラス内のメンバー (変数、メソッド) のアクセス修飾子は、上記の 4 つのいずれかになります。
- 一般的なデータ (メンバー変数) プライベート化 (プライベート) の動作 (メソッド) パブリック (パブリック))に慣れます。
- 継承関係にある親クラスの場合、その派生クラスを使用するには親クラスのリソースを呼び出す必要があるため、内部のアクセス許可は少なくとも保護されます。。
4.2 抽象クラス
4.2.1 コンセプト
Java では、メソッド本体なしでメソッドを定義できます。メソッド本体は、そのサブクラスによって特別に実装されます。メソッド本体を持たないメソッドを抽象メソッド、抽象メソッドを含むクラスを抽象クラスといいます。
抽象クラスは、メソッド宣言のみを持ち、メソッド本体を持たない特別なクラスとして理解できます。
公式:
//抽象方法,没有方法体,大括号也没有,有一个”;”。
修饰符 abstract 返回值类型 方法名(参数列表);
抽象クラスの意味: コードの共通機能を抽出し、サブクラスの継承を通じて拡張し、コード開発の効率を向上させることができます。。
例: 果物、物。。
class A{
public void eat(){
//声明一样,可以提取
syso("eat...B") }
}
class B{
public void eat(){
//声明一样,可以提取
syso("eat…A") }
}
abstract class C{
public abstract void eat();
}
4.2.2 特徴
- Java キーワードabstractを通じて実装されます。
- メソッドまたはクラスを変更できます。
- 抽象メソッドを含むクラスは抽象クラスである必要があり、抽象クラスには必ずしも抽象メソッドが含まれる必要はありません(抽象メソッドはサブクラスによって実装できるため)。
- 抽象クラス (サブクラスによって実装される) には抽象メソッドを含めることはできません。抽象メソッドまたは通常のメソッドを含めることができ、コンストラクター メソッドが存在する必要があります(サブクラスのインスタンス化用)、メンバー変数と定数を持つことができます。
- クラス内に抽象メソッドが存在する場合、そのクラスは抽象クラスとして定義する必要があります。
- サブクラスが抽象クラスを継承した後、(1) サブクラスは抽象クラスのままになるか、(2)
所有
親クラスのすべての抽象メソッドをオーバーライドします。 - 主にポリモーフィズムで使用されます。
- 抽象クラスは新しいオブジェクトによってインスタンス化できませんが、新しい配列にすることはできます。
抽象クラスにコンストラクター メソッドがあるのはなぜですか。これがないと、コンストラクターの最初のステートメントが暗黙的に super() を呼び出すため、サブクラスはコンパイルされません。。
要約を使用する場合の注意点:
- Abstract を使用してプロパティ、コンストラクター、その他の構造を変更することはできません。
- Abstract を使用して、プライベート メソッド、静的メソッド、最終メソッド、および最終クラスを変更することはできません。
概要: 同時に発生しない状況:
- fianl は固定で継承できないため、final と abstract を同時に出現させることはできません。abstract は
通常単独で使用されず、派生クラスと組み合わせて使用されます。 - this と super は両方のコンストラクターが最初の行にあるため、一緒に使用することはできません
- static が存在するときはオブジェクトが作成されていないため、static とこの super を同時に出現させることはできません。(main メソッドも静的メソッドなので、これを持つことはできません、スーパー)
注: 修飾子 Final static abstract は、ほとんどの場合 void よりも前に書かれます。
4.2.3 入門ケース
package cn.tedu.abstractdemo;
//测试抽象类的入门案例
public class Test1_Abstract {
public static void main(String[] args) {
//TODO 创建多态对象测试
//7,抽象类不能被实例化new 所以我们可以用多态实例它普通子类的对象
// Animal a = new Dog();
Animal a = new Cat();
a.eat();//狗吃肉
}
}
//创建父类
//3,如果类里有抽象方法,这个必须声明成一个抽象类
abstract class Animal{
//1, 父类提供的方法,如果子类要改,改的是方法体,但是要求方法声明不许改!!!(及:不用父类的方法体,甚至要覆盖它,可以不写父类的方法体就是抽象方法)
//这时,我们能不能只提供方法声明,不提供方法体 -- 可以,此时的方法就没有了方法体,称为抽象方法
//2, 通过abstract来修饰成抽象的
abstract public void eat() ;
//4,再提供一个抽象方法 和 普通方法
abstract public void game();
public void chiji() {
System.out.println("正在吃鸡");
}
}
//创建子类
//5,子类继承抽象后,子类可以把所有抽象方法 全都重写,那就是一个普通子类
class Cat extends Animal{
//重写所有抽象方法
// 注解:1,说明发生了方法的重写2.检出这个地方必须会发生重写,只有这个注解不写方法会报错
@Override //快捷键 @ alt+ /
//也可以直接,重写的方法名+alt+/
public void eat() {
System.out.println("猫吃鱼");
}
@Override
public void game() {
System.out.println("玩毛线");
}
}
//6,子类继承抽象后,没有把所有抽象方法 全都重写,那就是一个抽象子类
abstract class Dog extends Animal{
//重写抽象方法
@Override
public void eat() {
System.out.println("狗吃肉");
}
}
4.3 抽象クラスの使用法
4.3.1 施工方法
抽象クラスにもコンストラクターがありますが、それ自体をインスタンス化することはできません。
抽象クラスのコンストラクターは何に役立ちますか?
通常、サブクラスをインスタンス化するために使用されます。(サブクラスにはスーパーがあるため、デフォルトで親クラスのコンストラクターが呼び出されます。)
package cn.tedu.abstractdemo;
//测试抽象类构造方法的用法
public class Test2_UseAbstract {
public static void main(String[] args) {
//3,抽象类不能被实例化,那提供构造方法有啥用??--用来创建子类对象。
//原因是:子类创建对象时,构造方法里默认就会存在super()
// Animal2 a = new Animal2();
//TODO 创建多态对象测试
Animal2 a = new Dog2();
}
}
//创建父类
abstract class Animal2{
//1,可以有构造方法 -- 作用:用来创建对象
public Animal2() {
//最好手动提供一个无参构造
System.out.println("Animal2()...");
}
}
//创建子类
class Dog2 extends Animal2{
public Dog2() {
super();//2,默认就存在,会自动调用父类的构造方法
System.out.println("Dog2()...");
}
}
4.3.2 抽象クラスのメンバ変数と定数
変数と定数の両方を使用できます。
package cn.tedu.abstractdemo;
//测试抽象类的成员变量和常量的用法
public class Test2_UseAbstract {
public static void main(String[] args) {
//3,抽象类不能被实例化,那提供构造方法有啥用??--用来创建子类对象。88888888888888888
//原因是:子类创建对象时,构造方法里默认就会存在super()
// Animal2 a = new Animal2();
//TODO 创建多态对象测试
Animal2 a = new Dog2();
System.out.println(a.sum);//10
System.out.println(a.NAME);//xiongda
System.out.println(Animal2.NAME);//xiongda
}
}
//创建父类
abstract class Animal2{
//a,抽象类里可以提供成员变量
int sum = 10;
//b,抽象类里可以提供成员常量
static final String NAME="xiongda";
//1,提供构造方法 -- 作用:用来创建对象
public Animal2() {
System.out.println("Animal2()...");
}
}
//创建子类
class Dog2 extends Animal2{
public Dog2() {
super();//2,默认就存在,会自动调用父类的构造方法
System.out.println("Dog2()...");
}
}
4.3.3 抽象クラスのメンバメソッド
- 抽象クラスには、通常のメソッドと抽象メソッドの両方が存在できます。。
- すべての抽象クラスは通常のメソッドを持つことができますか? – はい
- 抽象クラス内のすべてのメソッドが通常のメソッドである場合、なぜそれらを抽象クラスに変更する必要があるのでしょうか? - 外部の世界に new を許可しない (外部の世界がオブジェクトをインスタンス化するのを許可しない)
- 抽象クラスに通常のメソッドは存在できますか? – はい
- 抽象クラスはインスタンス化できますか? – いいえ
- 抽象クラスは特別なクラスですが、何がそんなに特別なのでしょうか? – 抽象メソッドを含めることができます
- 抽象クラスに通常のメソッドを提供するか抽象メソッドを提供するかをどのように決定するか? – メソッド本体を提供するかどうかを確認する
- テスト:
package cn.tedu.oop;
//测试 抽象类 成员方法
public class Test1_UseAbstract {
public static void main(String[] args) {
//创建多态对象测试
Fu fu = new Zi();
fu.eat();
fu.sleep();
fu.game();
}
}
//2, 如果类中包含抽象方法,那么,这个类必须修饰成 抽象类
//3, 抽象类是一个特殊的类 ,比较灵活. 特殊在 : 抽象类里可以有抽象方法 , 也可以有普通方法 .
//到底是普通方法还是抽象方法,看你要不要提供方法体了.
abstract class Fu{
//4, 这个方法是最终方法,不能被子类重写!!
final public void eat() {
System.out.println("爸爸在吃肉");
}
//1 , sleep被子类继承,并且发生了方法重写,也就是想改父类的方法体.---父类就不提供方法体了,就变成了抽象方法
abstract public void sleep() ;
abstract public void game() ;
}
//5 , 子类继承抽象类以后,可以 重写所有的抽象方法 , 否则 , 子类就包含着抽象方法是一个抽象子类
class Zi extends Fu{
@Override
public void sleep() {
System.out.println("Zi...sleep()");
}
@Override
public void game() {
System.out.println("Zi...game()");
}
}
4.4 抽象クラスの匿名サブクラス
package com.cn.per;
/*
* 抽象类的匿名子类:凡是匿名的作用都是为了省事,只用一次。
* 匿名子类:不用在创建类继承抽象父类后再重写方法,直接在new对象的同时重写方法,简化了代码。
*
*/
public class PersonTest {
public static void main(String[] args) {
method(new Student());//普通类的匿名对象
Worker worker = new Worker();
method1(worker);//普通类的普通对象
method1(new Worker());//普通类的匿名对象
System.out.println("********************");
//创建了一匿名子类的普通对象:p
/*
* 省略class Worker extends Person{......},
* 直接创建对象的时候重写抽象父类的抽象方法即可,不用在单独的创建类继承后再重写抽象方法。
*/
Person p = new Person(){
//注意:这里是创建了没有名字的子类对象,不是父类的对象Person。person是抽象类也不能够创建对象。
@Override
public void eat() {
System.out.println("吃东西");
}
@Override
public void breath() {
System.out.println("好好呼吸");
}
};
method1(p);
System.out.println("********************");
//创建匿名子类的匿名对象
method1(new Person(){
@Override
public void eat() {
System.out.println("吃好吃东西");
}
@Override
public void breath() {
System.out.println("好好呼吸新鲜空气");
}
});
} //main方法的结束符
public static void method1(Person p){
p.eat();
p.breath();
}
public static void method(Student s){
}
}
class Worker extends Person{
//用了匿名子类的对象这一步可省略
@Override
public void eat() {
}
@Override
public void breath() {
}
}
package com.cn.per;
/*
* abstract关键字的使用
* 1.abstract:抽象的
* 2.abstract可以用来修饰的结构:类、方法
*
* 3. abstract修饰类:抽象类
* > 此类不能实例化
* > 抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化的全过程)
* > 开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作
*
*
* 4. abstract修饰方法:抽象方法
* > 抽象方法只有方法的声明,没有方法体
* > 包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法的。
* > 若子类重写了父类中的所有的抽象方法后,此子类方可实例化
* 若子类没有重写父类中的所有的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰
*/
public class AbstractTest {
public static void main(String[] args) {
//一旦Person类抽象了,就不可实例化
// Person p1 = new Person();
// p1.eat();
}
}
abstract class Creature{
public abstract void breath();
}
abstract class Person extends Creature{
String name;
int age;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
//不是抽象方法:
// public void eat(){
//
// }
//抽象方法
public abstract void eat();
public void walk(){
System.out.println("人走路");
}
}
class Student extends Person{
public Student(String name,int age){
super(name,age);
}
public Student(){
}
public void eat(){
System.out.println("学生多吃有营养的食物");
}
@Override
public void breath() {
System.out.println("学生应该呼吸新鲜的没有雾霾的空气");
}
}
4.5 抽象クラスの適用:テンプレートメソッドの設計パターン
package com.atguigu.java;
/*
* 抽象类的应用:模板方法的设计模式
*
*/
public class TemplateTest {
public static void main(String[] args) {
SubTemplate t = new SubTemplate();
t.spendTime();
}
}
abstract class Template{
//计算某段代码执行所需要花费的时间
public void spendTime(){
long start = System.currentTimeMillis();
this.code();//不确定的部分、易变的部分
long end = System.currentTimeMillis();
System.out.println("花费的时间为:" + (end - start));
}
public abstract void code();
}
class SubTemplate extends Template{
@Override
public void code() {
for(int i = 2;i <= 1000;i++){
boolean isFlag = true;
for(int j = 2;j <= Math.sqrt(i);j++){
//开方
if(i % j == 0){
isFlag = false;
break;
}
}
if(isFlag){
System.out.println(i);
}
}
}
}
4.6 外部がオブジェクトをインスタンス化するのを防ぐ方法 (2 つの方法)
- クラスを抽象クラスに変更します。
- コンストラクターをプライベートにする
4.7 メンバ変数に値を代入する方法(2通り)
1. setXxx() を呼び出します。
2. コンストラクターメソッドを使用して値を代入します(オブジェクト作成時にコンストラクターメソッドが呼び出され、渡された値がコンストラクターメソッド内のメンバー変数に代入されます)
理由:値を直接割り当てないのは、コードがハードコーディングされており、柔軟性が低いためです。
5 Day10 – オブジェクト指向 5
5.1 インターフェース (デフォルトの新機能)
5.1.1 コンセプト
Javaでは多重継承が認められていないため、複数のクラスの機能を実装したい場合は、複数のインターフェースを実装することで実現できます。
Java接口
および Java は抽象类
抽象型を表します。これは、提案する必要がある抽象化層の具体的な表現です。OOP面向对象
プログラミング、プログラムの再利用率を高め、プログラムの保守性や拡張性を高めたい場合は、インターフェース指向プログラミングと抽象化指向プログラミングでなければなりません。、インターフェイスや抽象クラスなどの有用な抽象型を Java 構造の最上位層として正しく使用します。
文法:
interface 接口名{
代码…
}
abstract class 类名{
代码…
} //2单词变成了一个
5.1.2 特徴
- インターフェイス内のメソッドはすべてパブリック抽象メソッドであり、変数はすべてパブリック定数であり、コンストラクターはありません。(インターフェース内のリソースはすべて public です)。
- Interface キーワードを使用してインターフェイスを作成する
- サブクラスがimplementsを介して実装できるようにします(抽象クラスは継承を拡張します)
- インターフェースが特殊な抽象クラスであることがわかります。
- Java の単一継承の制限を突破するインターフェース
- インターフェイスとクラスには複数の実装を含めることができ、インターフェイスには複数の継承 (「,」で区切る) を含めることができ、継承は同時に複数の実装にすることができますが、同時に複数の継承と複数の実装をしたり、順序を変更したりすることはできません。最初に実装してから継承します。(概要: 同じ型は継承であり、違いは実装関係です。)
- インターフェイスは、外部公開のルールと一連の開発仕様です。
- インターフェースはプログラムの機能拡張を改善し、結合を減らします(結合はプログラムの相関関係であり、相関が低いほど良い)
注:
- インターフェイス継承インターフェイスを呼び出すにはどうすればよいですか?インターフェイスはインスタンス化できない特殊な抽象クラスであるため、このインターフェイスを実装し、この実装クラスをインスタンス化するための共通のサブクラスを作成することしかできません。
- 注意してくださいインターフェイス内の抽象メソッドをオーバーライドする権限、デフォルトは public であるため、サブクラスの権限は少なくとも public と同等になります (2 は 2 と同じで、小さいほど大きいという原則)。
- インターフェイスの新しいデフォルト機能: jdk 1.8 以降、インターフェイスは、静的またはデフォルトのデフォルトで変更された通常のメソッド (静的メソッドとデフォルトのメソッド) を持つことができます (デフォルトは省略されません)。
- インターフェースに通常のメソッドが存在するということは、抽象クラスに抽象メソッドがたくさんあるとサブクラスで書き換えるのが面倒になるので、通常のメソッドで書き換えたい場合には書き換えるのが便利ということです。
- サブクラスは抽象親クラスを継承し、親クラスのメソッドをオーバーライドします。これをメソッドの書き換えと呼びます。
サブクラスはインターフェイスを実装し、インターフェイス メソッドをオーバーライドします。これはメソッド実装と呼ばれます。もちろん、それを書き換えと呼ぶのは問題ありませんが、それは正確ではありません。
5.1.3 はじめに ケース 1
package cn.tedu.interfacedemo;
//接口的入门案例
public class Test4_Inter {
public static void main(String[] args) {
//TODO 创建多态对象测试
//5,接口可以创建对象吗??? --- 不能!!!和抽象类一样,不能实例化
// Inter i = new Inter();
Inter i = new InterImpl();
i.delete();
i.save();
}
}
//创建接口
//1,通过interface关键字定义接口
interface Inter{
//2,接口里可以有普通方法吗???---不可以!!!接口里都是抽象方法
abstract public void delete();
abstract public void save();
}
//3,实现类,想要使用接口里的功能,需要 实现 接口,用implements关键字
//4, 实现类实现了接口以后,可以是一个普通实现类,就要求重写所有抽象方法
class InterImpl implements Inter{
//重写所有抽象方法(注意抽象方法有分号,没有方法体,连{}也没有)
//重写的方法把它变为普通的方法,把abstract去掉,写方法体,注意分号。
@Override
public void delete() {
System.out.println("delete()...");
}
@Override
public void save() {
System.out.println("save()...");
}
}
//实现类一般都是在接口上加 Impl
//6, 实现类实现了接口以后,如果没有全部重写抽象方法,就是个抽象子类
abstract class InterImpl2 implements Inter{
}
5.1.4 入門ケース 2
package com.atguigu.java1;
/*
* 接口的使用
* 1.接口使用interface来定义
* 2.Java中,接口和类是并列的两个结构
* 3.如何定义接口:定义接口中的成员
*
* 3.1 JDK7及以前:只能定义全局常量和抽象方法
* >全局常量:public static final的.但是书写时,可以省略不写
* >抽象方法:public abstract的
*
* 3.2 JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法(略)
*
* 4. 接口中不能定义构造器的!意味着接口不可以实例化
*
* 5. Java开发中,接口通过让类去实现(implements)的方式来使用.
* 如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化
* 如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类
*
* 6. Java类可以实现多个接口 --->弥补了Java单继承性的局限性
* 格式:class AA extends BB implements CC,DD,EE
*
* 7. 接口与接口之间可以继承,而且可以多继承
*
* *******************************
* 8. 接口的具体使用,体现多态性
* 9. 接口,实际上可以看做是一种规范
*
* 面试题:抽象类与接口有哪些异同?
*
*/
public class InterfaceTest {
public static void main(String[] args) {
System.out.println(Flyable.MAX_SPEED);
System.out.println(Flyable.MIN_SPEED);
// Flyable.MIN_SPEED = 2;
Plane plane = new Plane();
plane.fly();
}
}
interface Flyable{
//全局常量
public static final int MAX_SPEED = 7900;//第一宇宙速度
int MIN_SPEED = 1;//省略了public static final
//抽象方法
public abstract void fly();
//省略了public abstract
void stop();
//Interfaces cannot have constructors
// public Flyable(){
//
// }
}
interface Attackable{
void attack();
}
class Plane implements Flyable{
@Override
public void fly() {
System.out.println("通过引擎起飞");
}
@Override
public void stop() {
System.out.println("驾驶员减速停止");
}
}
abstract class Kite implements Flyable{
@Override
public void fly() {
}
}
class Bullet extends Object implements Flyable,Attackable,CC{
@Override
public void attack() {
// TODO Auto-generated method stub
}
@Override
public void fly() {
// TODO Auto-generated method stub
}
@Override
public void stop() {
// TODO Auto-generated method stub
}
@Override
public void method1() {
// TODO Auto-generated method stub
}
@Override
public void method2() {
// TODO Auto-generated method stub
}
}
//************************************
interface AA{
void method1();
}
interface BB{
void method2();
}
interface CC extends AA,BB{
}
5.1.5 プレゼンテーション インターフェイスは正規の匿名実装クラス オブジェクトです
インターフェイスの匿名実装クラスは、抽象クラスの匿名サブクラスと同じように使用されます。
package com.atguigu.java1;
/*
* 接口的使用
* 1.接口使用上也满足多态性
* 2.接口,实际上就是定义了一种规范
* 3.开发中,体会面向接口编程!
*
*/
public class USBTest {
public static void main(String[] args) {
Computer com = new Computer();
//1.创建了接口的非匿名实现类的非匿名对象
Flash flash = new Flash();
com.transferData(flash);
//2. 创建了接口的非匿名实现类的匿名对象
com.transferData(new Printer());
//3. 创建了接口的匿名实现类的非匿名对象
USB phone = new USB(){
@Override
public void start() {
System.out.println("手机开始工作");
}
@Override
public void stop() {
System.out.println("手机结束工作");
}
};
com.transferData(phone);
//4. 创建了接口的匿名实现类的匿名对象
com.transferData(new USB(){
@Override
public void start() {
System.out.println("mp3开始工作");
}
@Override
public void stop() {
System.out.println("mp3结束工作");
}
});
}
}
class Computer{
public void transferData(USB usb){
//USB usb = new Flash();
usb.start();
System.out.println("具体传输数据的细节");
usb.stop();
}
}
interface USB{
//常量:定义了长、宽、最大最小的传输速度等
void start();
void stop();
}
class Flash implements USB{
@Override
public void start() {
System.out.println("U盘开启工作");
}
@Override
public void stop() {
System.out.println("U盘结束工作");
}
}
class Printer implements USB{
@Override
public void start() {
System.out.println("打印机开启工作");
}
@Override
public void stop() {
System.out.println("打印机结束工作");
}
}
5.2 インターフェースの使用法
5.2.1 施工方法
インターフェイスにはコンストラクター メソッドがありません。実装クラスのオブジェクトを作成する場合、デフォルトの super() は、呼び出されるデフォルト オブジェクトのパラメーターなしのコンストラクターです。
public interface Inter2 {
//接口里可以有构造方法吗???--没有!!,抽象类有
// public Inter2() {}
}
5.2.2 メンバー変数
- インターフェイス内のリソースはすべてパブリックであり、public で変更されます。
- インターフェイス変数は、デフォルトでは静的定数です。
- 概要: インターフェイス内の変数はすべて
公共的 静态 常量
。
例:
public static final int age;
等价于:
int age; //接口中会默认自动拼接 public static final
5.2.3 インターフェースのメンバーメソッド
- インターフェイス内のリソースはすべてパブリックであり、public で変更されます。
- インターフェース内のメソッドはデフォルトでabstractになっており、書かなくてもデフォルトで結合されますが表示されません。
- 概要: インターフェイス内のすべてのメソッドは、
公共的 抽象 方法
記述されていない場合でもデフォルトで結合されますが、表示されません。。
例:
public abstract void save();
等价于:
void save(); //会默认拼接 public abstract
5.3 インターフェースの複雑な使用法
Java における単一継承の制限は、インターフェイスを通じて解決できます。接口可以多继承也可以多实现,甚至可以继承的同时多实现。
package cn.tedu.interfacedemo;
//这个类用来测试接口的复杂用法:多继承多实现
public class Test4_ComInter {
public static void main(String[] args) {
Interface1 in = new Interface1Impl();
in.save();
in.update();
}
}
//创建接口1
interface Interface1{
void save();
void update();
}
//创建接口2
interface Interface2{
void get();
void delete();
}
//1、打破了java单继承的局限性,因为接口之间可以多继承,多个接口之间逗号隔开
interface Interface3 extends Interface1,Interface2{
void add();
}
//3、接口还可以多实现吗??---可以多实现,只不过接口之间逗号隔开
class ManyImpl implements Interface1,Interface2{
public void save() {
}
public void update() {
}
public void get() {
}
public void delete() {
}
}
//4、接口可以继承的同时,多实现?? --
class MoreImple extends ManyImpl implements Interface1,Interface2 {
}//注意:只能是先继承在多实现。顺序不能变,并且不能多继承多实现。
//2、创建实现类,使用3号接口的功能,需要重写几个方法呢??---同时重写1号和2号和3号接口里的所有功能
class Interface3Impl implements Interface3{
@Override
public void save() {
}
@Override
public void update() {
}
@Override
public void get() {
}
@Override
public void delete() {
}
@Override
public void add() {
}
}
//TODO 创建实现类
class Interface1Impl implements Interface1{
@Override
public void save() {
System.out.println("save()...");
}
@Override
public void update() {
System.out.println("update()...");
}
}
5.4 インターフェースでの jdk1.8 の新機能の使用
クラスサブクラステスト:
package com.atguigu.java8;
public class SubClassTest {
public static void main(String[] args) {
SubClass s = new SubClass();
// s.method1();
// SubClass.method1();
//知识点1:接口中定义的静态方法,只能通过接口来调用。
CompareA.method1();
//知识点2:通过实现类的对象,可以调用接口中的默认方法。
//如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法
s.method2();
//知识点3:如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的默认方法,
//那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法。-->类优先原则
//知识点4:如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,
//那么在实现类没有重写此方法的情况下,报错。-->接口冲突。
//这就需要我们必须在实现类中重写此方法
s.method3();
}
}
class SubClass extends SuperClass implements CompareA,CompareB{
public void method2(){
System.out.println("SubClass:上海");
}
public void method3(){
System.out.println("SubClass:深圳");
}
//知识点5:如何在子类(或实现类)的方法中调用父类、接口中被重写的方法
public void myMethod(){
method3();//调用自己定义的重写的方法
super.method3();//调用的是父类中声明的
//调用接口中的默认方法
CompareA.super.method3();
CompareB.super.method3();
}
}
インターフェース比較A:
package com.atguigu.java8;
/*
*
* JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法
*
*/
public interface CompareA {
//静态方法
public static void method1(){
System.out.println("CompareA:北京");
}
//默认方法
public default void method2(){
System.out.println("CompareA:上海");
}
default void method3(){
System.out.println("CompareA:上海");
}
}
インターフェース比較B:
package com.atguigu.java8;
public interface CompareB {
default void method3(){
System.out.println("CompareB:上海");
}
}
クラススーパークラス:
package com.atguigu.java8;
public class SuperClass {
public void method3(){
System.out.println("SuperClass:北京");
}
}
5.5 インターフェース 1 の適用: プロキシモード
package com.atguigu.java1;
/*
* 接口的应用:代理模式
* 以下代码为:静态代理模式
*
*/
public class NetWorkTest {
public static void main(String[] args) {
Server server = new Server();
// server.browse();
ProxyServer proxyServer = new ProxyServer(server);
proxyServer.browse();
}
}
interface NetWork{
public void browse();
}
//被代理类
class Server implements NetWork{
@Override
public void browse() {
System.out.println("真实的服务器访问网络");
}
}
//代理类
class ProxyServer implements NetWork{
private NetWork work;
public ProxyServer(NetWork work){
this.work = work;
}
public void check(){
System.out.println("联网之前的检查工作");
}
@Override
public void browse() {
check();
work.browse();
}
}
5.6 インターフェース 2 の適用: ファクトリーモード
ファクトリ パターン: 作成者と呼び出し者の分離を実現します。つまり、オブジェクト作成の特定のプロセスをシールドおよび分離して、柔軟性を向上させるという目的を達成します。
ファクトリ: オブジェクトの作成に使用されます。
工場パターンの分類:
- 単純な工場モデル: 同じ階層構造で任意の製品を生産するために使用されます。(新しい製品を追加するには、既存のコードを変更する必要があります)
- ファクトリメソッドパターン: 同じ階層構造で固定製品を生産するために使用されます。(任意の製品の追加をサポート)
- 抽象的な工場パターン: さまざまな製品ファミリーのすべての製品を生産するために使用されます。(新しい製品の追加については何もできません。製品ファミリーの追加はサポートされています)
5.7 デザインパターンの最初の紹介
Java には 23 の設計パターンがあり、これらは本質的にオブジェクト指向の設計原則を実際に適用し、クラスのカプセル化、継承、ポリモーフィズム、およびクラスの関連付けと組み合わせ関係を完全に理解したものです。
もちろん、ソフトウェア設計パターンは単なるガイドであり、実際のソフトウェア開発では、特定のニーズに応じて選択する必要があります。
1. 単純なプログラムの場合、特定の設計パターンを導入するよりも単純なアルゴリズムを作成する方が簡単な場合があります。
2. ただし、大規模なプロジェクト開発やフレームワーク設計の場合は、デザイン パターンを使用してコードを整理する方が明らかに優れています。
5.7.1 シングルトン設計パターンの概念
シングルトン モードは、ほとんどの開発者が実際に最もよく使用しているモードであると言え、Spring で作成された共通 Bean はシングルトン モードです。
シングルトン モードには、システム メモリ領域の節約やリソース使用量の制御など、多くの利点があります。
シングルトン パターンで最も重要なことは、オブジェクトが 1 つだけ存在するようにすることです。
簡単に言うと、メモリ内にクラスのオブジェクトが 1 つだけ存在することが保証されます。
RunTime は典型的なシングルトン設計であり、RunTime クラスの分析を通じてそれを垣間見ることができます。
5.7.2 ソースコード解析
/**
* Every Java application has a single instance of class
* <code>Runtime</code> that allows the application to interface with
* the environment in which the application is running. The current
* runtime can be obtained from the <code>getRuntime</code> method.
* <p>
* An application cannot create its own instance of this class.
*
* @author unascribed
* @see java.lang.Runtime#getRuntime()
* @since JDK1.0
*/
RunTime.java
package java.lang;
public class Runtime {
//1、创建静态的全局唯一的对象
private static Runtime currentRuntime = new Runtime();
//2、私有构造方法,
/** Don't let anyone else instantiate this class */
private Runtime() {
}
//3、通过自定义的静态方法获取实例
public static Runtime getRuntime() {
return currentRuntime;
}
}
5.7.3 お腹を空かせた中華風
目的: 外部によって作成されるオブジェクトの数を制御するために、作成できるオブジェクトは 1 つだけです。
開発手順:
1. コンストラクターをプライベート化します。
2. クラス内にオブジェクトを作成します
。 3. パブリック get() を外部に提供し、準備されたオブジェクトを返します。コンストラクターがプライベートになったため、外部からメソッドを呼び出すオブジェクトを作成することはできず、クラス名を使用して呼び出せるのは、静的として宣言されたメソッドのみです。
4.スレッドの安全性の問題はありません
package cn.tedu.single;
//测试单例设计模式
public class Test8_Single {
public static void main(String[] args) {
Single s = Single.get();
Single s1 = Single.get();
//get()多少次,内存中使用的都是同一个对象
System.out.println(s);//cn.tedu.single.Single@15db9742
System.out.println(s1);//cn.tedu.single.Single@15db9742
}
}
class Single{
// 1、私有化构造方法,不让外界直接new
private Single() {
}
// 2、在类的内部,创建好对象
//static :静态只能调用静态,因为方法是静态的调用这对象属性也只能是静态的。
static private Single s = new Single();
// 3、对外界提供一个公共的get(),返回一个已经准备好的对象
//static是为了外界不通过对象访问而是通过类名直接方法
static public Single get(){
//注意:静态只能调用静态
return s;
}
}
5.7.4 怠け者のスタイル
遅延スタイルにはスレッドの安全性の問題があります - 「day05-Java 高度なプログラミングで解決されました」 - 同期ロック。
注: 面接中、シングルトン デザイン パターンを作成する必要があります。つまり、ハングリー チャイニーズ スタイルを作成するか、スレッド セーフな遅延スタイルを作成するか、スレッド セーフでない遅延スタイルを作成しないでください。
class Single{
// 1、私有化构造方法,不让外界直接new
private Single() {
}
// 2、在类的内部,创建好对象
//static :静态只能调用静态
static private Single s = null;
// 3、对外界提供一个公共的get(),返回一个已经准备好的对象
//static是为了外界不通过对象访问而是通过类名直接方法
static public Single get(){
//注意:静态只能调用静态
if(s==null){
/*会有线程安全问题:假如现在多个线程,每个线程调用run方法,各个run方法有调用这个get方法。
当第一个线程进入到这个get方法后,第一次进入对象为空,此时可能发生阻塞第二个线程进来判断为空
也需要创建对象。这样就创建了2个对象不合理。s相当于共享数据。
*/
//如何解决?查看在day05--java高级编程---》同步锁中解决。
s = new Single();
}
return s;//是null说明还没有创建对象,不是null说明创建好了对象直接返回,可以保证只创建一次对象。
}
}
5.7.5 飢えた男のスタイルと怠け者のスタイルの違い
お腹を空かせた中華風:
- 欠点: オブジェクトの読み込みに時間がかかりすぎます。
- 利点: Hungry Chinese Style はスレッドセーフです
怠け者のスタイル:
- 利点: オブジェクトの作成が遅れます。
- 現在の書き方の欠点: スレッドが安全ではありません。—> マルチスレッドコンテンツに到達したら、再度変更します (同期ロックを追加します)。
5.7.6 シングルトン設計パターンの適用シナリオ
5.8 拡張
5.8.1 要約注記
抽象メソッドでは、継承後にサブクラスがオーバーライドする必要があります。では、abstract キーワードと一緒に使用できないキーワードはどれでしょうか? 次のキーワードは抽象クラスで使用できますが、意味はありません。
1. プライベート: プライベート化された後は、サブクラスを書き換えることはできません。これは抽象に反します。
2. static: 静的、オブジェクトの存在よりも優先されます。抽象メソッドはサブクラスで書き直す必要がありますが、静的メソッドはオーバーライドできないため、この 2 つは矛盾します。
3. Final: Final によって変更された後は、要約に反して書き換えることはできません。
5.8.2 インターフェースと抽象クラスの違い
1. 抽象クラスもインターフェイスも直接インスタンス化することはできません。インスタンス化する場合、抽象クラス変数はすべての抽象メソッドを実装するサブクラス オブジェクトを指し、インターフェイス変数はすべてのインターフェイス メソッドを実装するクラス オブジェクトを指す必要があります。
2. 抽象クラスはサブクラスによって継承され、インターフェイスはクラスによって実装される必要があります。
3. インターフェイスはメソッド宣言のみを行うことができますが、抽象クラスはメソッド宣言とメソッド実装を行うことができます
4. インターフェイスで定義された変数は public static 定数のみにすることができますが、抽象クラスの変数は通常の変数です。
5. 抽象クラス内のすべての抽象メソッドはサブクラスで実装する必要があります。サブクラスが親クラスのすべての抽象メソッドを実装できない場合、サブクラスは抽象クラスのみになります。同様に、クラスがインターフェイスを実装する場合、すべてのインターフェイス メソッドを実装できない場合、そのクラスは抽象クラスのみになります。
6. 抽象メソッドは宣言のみ可能であり、実装はできません。インターフェイスは設計の結果であり、抽象クラスは再構築の結果です。 7. 抽象クラスには抽象メソッドはありません。抽象クラスの新しいメソッドを拡張したい場合は
、これらの新しいメソッドが利用可能です。
8. クラスに抽象メソッドがある場合、そのクラスは抽象クラスのみになります。
9. 抽象メソッドは実装する必要があるため、静的またはプライベートにすることはできません。
10. インターフェイスはインターフェイスを継承でき、複数のインターフェイスを継承できますが、クラスは単一のルートからのみ継承できます。
5.8.3 ソフトウェア設計のオープンとクローズの原則 OCP を理解する
オープン機能拡張、クローズソースコード修正など。
オープン・クローズ原則の英語の正式名は Open Close Principle、略称は OCP であり、Java の世界で最も基本的な設計原則であり、安定した柔軟なシステムを構築するための指針となります。
オープンクローズ原則の定義は次のとおりです。ソフトウェア内のオブジェクト (クラス、モジュール、関数など) は拡張に対してオープンである必要がありますが、変更に対してはクローズされている必要があります。
開閉原理は、オブジェクト指向プログラミングの考え方から生まれたデザインパターンです。
オープンとは、継承、インターフェイス、抽象クラスなど、ソース コードに基づいて拡張できることを意味します。JAVA では、クラス ライブラリを直接呼び出すことを前提として、クラス ライブラリの機能を拡張するために継承が使用されます。アプリケーションは、開発のためにカプセル化されたクラスの内部ロジックを理解する必要はありません。
Closed: 元のコードの変更が許可されていないことを意味します。他の既存の機能に影響を与え、機能麻痺を引き起こさないようにするため。
5.8.4 パイルとデバッグ
プログラムの結果が予想したものと異なる場合、どうやってコードをデバッグしますか?
(1) パイル: System.out.println(data);
(2) デバッグ デバッグ ツール: 簡単に説明します。詳細については、ブログのチャット欄を参照してください。
5.8.5 Math クラスは 3 つのポジティブ メソッドを提供します: ceil、floor、round
書き方:
System.out.println(Math.ceil(11.5));//12.0
(1) ceil の英語の意味は天井であり、この方法は切り上げを意味します
(2) Floor の英語の意味は床であり、この方法は切り捨てを意味します
(3) Round メソッド:「四捨五入」を意味します (例:+0.5切り捨て)
6 例外
6.1 例外の概要
-
出現の背景:
コンピュータ言語を使用したプロジェクト開発のプロセスでは、プログラマーがコードをうまく書いたとしても尽善尽美
、システムの運用中にいくつかの問題に遭遇することがあります。これは、コードに依存するだけでは回避できない問題が多いためです客户输入数据的格式,读取文件是否存在,网络是否始终保持通畅
。 -
例外:
Java 言語では、プログラムの実行中に発生する異常な状況を「例外」と呼びます。(開発時の構文エラーや論理エラーも例外ではありません)
6.2 システムの異常
説明:
Throwable
: Java では、すべての例外には共通の祖先 Throwable (throwable) があります。Error
: 深刻な問題なので、対処する必要はありませんException
: 例外クラスと呼ばれ、プログラム自体で処理できる問題を表します。RuntimeException
: コンパイル時にチェックされないため、問題が発生した場合は、戻ってコードを修正する必要があります。非RuntimeException
: コンパイル中に処理する必要があります。そうしないと、プログラムはコンパイルできず、ましてや正常に実行できません。
6.2.1 エラー例
package com.atguigu.java;
/*
* Error:
* Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。比如:StackOverflowError和OOM。
*
* 一般不编写针对性的代码进行处理。出现问题只能改代码。
*
*
*/
public class ErrorTest {
public static void main(String[] args) {
//1.栈溢出:java.lang.StackOverflowError
// main(args);
//2.堆溢出:java.lang.OutOfMemoryError
Integer[] arr = new Integer[1024*1024*1024];
}
}
6.2.2 例外の例
package com.atguigu.java1;
import java.io.File;
import java.io.FileInputStream;
import java.util.Date;
import java.util.Scanner;
import org.junit.Test;
/*
* 一、异常体系结构
*
* java.lang.Throwable
* |-----java.lang.Error:一般不编写针对性的代码进行处理。
* |-----java.lang.Exception:可以进行异常的处理
* |------编译时异常(checked)
* |-----IOException
* |-----FileNotFoundException
* |-----ClassNotFoundException
* |-----SQLException sql异常
* |------运行时异常(unchecked,RuntimeException)
* |-----NullPointerException
* |-----ArrayIndexOutOfBoundsException
* |-----ClassCastException
* |-----NumberFormatException 数字格式异常
* |-----InputMismatchException 输入不匹配异常
* |-----ArithmeticException 算术异常
*
*
*
* 面试题:常见的异常都有哪些?举例说明
*/
public class ExceptionTest {
//******************以下是编译时异常***************************
@Test
public void test7(){
// File file = new File("hello.txt");
// FileInputStream fis = new FileInputStream(file);
//
// int data = fis.read();
// while(data != -1){
// System.out.print((char)data);
// data = fis.read();
// }
//
// fis.close();
}
//******************以下是运行时异常***************************
//ArithmeticException
@Test
public void test6(){
int a = 10;
int b = 0;
System.out.println(a / b);
}
//InputMismatchException
@Test
public void test5(){
Scanner scanner = new Scanner(System.in);
int score = scanner.nextInt();
System.out.println(score);
scanner.close();
}
//NumberFormatException
@Test
public void test4(){
String str = "123";
str = "abc";
int num = Integer.parseInt(str);
}
//ClassCastException
@Test
public void test3(){
Object obj = new Date();
String str = (String)obj;
}
//IndexOutOfBoundsException
@Test
public void test2(){
//ArrayIndexOutOfBoundsException
// int[] arr = new int[10];
// System.out.println(arr[10]);
//StringIndexOutOfBoundsException
String str = "abc";
System.out.println(str.charAt(3));
}
//NullPointerException
@Test
public void test1(){
// int[] arr = null;
// System.out.println(arr[3]);
String str = "abc";
str = null;
System.out.println(str.charAt(0));
}
}
6.3 JVM のデフォルトの処理ソリューション
プログラムに問題があり、何もしなかった場合、最終的には JVM がデフォルトの処理を実行します。
- 例外の名前、例外の原因、例外の場所などの情報がコンソールに出力されます(下図からわかるように)
- プログラムは実行を停止します (下の図からわかるように、
结束
コンソールに出力はありません)。
6.4 Throwableのメンバーメソッド
6.5 コンパイル時例外と実行時例外の違い
Java の例外は、次の 2 つの主要なカテゴリに分類されます。编译时异常
と运行时异常
、 および とも受检异常
呼ば非受检异常
れます。 すべての RuntimeException クラスとそのサブクラスは実行時例外と呼ばれ、その他の例外はコンパイル時例外と呼ばれます。
- コンパイル時例外: 明示的に処理する必要があります。そうでないと、プログラムでエラーが発生し、コンパイルに失敗します。
- 実行時例外: 明示的な処理は必要なく、コンパイル時例外と同じ方法で処理できます。
6.6 例外処理の概要
-
例外処理が必要な理由:
Java 仮想マシンのデフォルトの処理スキームにより、例外が発生した時点でプログラムが直接終了するためです。実際の開発では、プログラムの特定の部分で問題が発生しても、その後の実行には影響しないはずなので、例外を自分で処理する必要があります。 -
プログラムに問題がある場合は、自分たちで対処する必要があります。選択肢は 2 つあります。
- 試してみて…捕まえて…
- 投げる
-
例外処理:キャッチ&スローモデル
- 処理1:「スロー」:通常のプログラム実行時に例外が発生すると、例外コードの部分に例外オブジェクトが生成され、そのオブジェクトがスローされます。例外オブジェクトがスローされると、
其后的代码就不会再执行。
- 例外オブジェクトの生成について:
① システムが自動生成する例外オブジェクト
② 手動で例外オブジェクトを生成してスローする(throw)
- 例外オブジェクトの生成について:
- 処理 2 : 「キャッチ」: 例外処理メソッドとして理解できます。
- try-catch-finally: 実際の例外処理、後続のコード
会执行
- throws: 例外は実際には処理されず、呼び出し元、後続のコードにスローされるだけです。
不会执行
- try-catch-finally: 実際の例外処理、後続のコード
- 処理1:「スロー」:通常のプログラム実行時に例外が発生すると、例外コードの部分に例外オブジェクトが生成され、そのオブジェクトがスローされます。例外オブジェクトがスローされると、
-
プログラム内で例外が発生し、処理されない場合:
- 最終的には main メソッドに到達します。main メソッドは jvm 仮想マシンによって管理されます。jvm 仮想マシンはプロセスを強制終了してプログラムを終了することによって例外を処理します。
-
例外処理の意味:
- 例外が発生した後でも、プログラムの動作に影響を与えることなく、プログラムを正しく実行できます。
6.7 例外処理方法 1:(try-catch-finally)
説明:
- try-catch-finally、キャプチャ モードとも呼ばれます。
構文:
//try只能而且出现一次 catch可以出现0到N次 finally出现0到1次
try{
//可能出现异常的代码
}catch(异常类型1 变量名1){
//处理异常的方式1
}catch(异常类型2 变量名2){
//处理异常的方式2
}catch(异常类型3 变量名3){
//处理异常的方式3
}
....
finally{
//一定会执行的代码
}
実装プロセス:
- プログラムは try のコードから実行を開始します
出现异常,会自动生成一个异常类对象
、例外オブジェクトは Java ランタイム システムに送信されます。- Java ランタイム システムは例外オブジェクトを受け取ると、キャッチに移動して一致する例外クラスを見つけ、見つけた後に例外を処理します。
执行完毕之后,程序还可以继续往下执行
。
6.7.1 テスト 1: try-catch 構造
package com.shuai;
/**
* 1.finally是可选的。
*
* 2.使用try将可能出现异常代码包装起来,在执行过程中,一旦出现异常就会生成一个对应类的异常对象,根据
* 此对象的类型到catch中进行匹配。
*
* 3.一旦try中的异常对象匹配到一个catch时,就进入catch中进行异常的处理,一旦处理完成,就跳出当前的
* try-catch结构(在没有写finally的情况),继续执行其后的代码。
*
* 4.catch中的异常类型如果没有父子类关系,谁声明在上,,谁声明在下无所谓。
* catch中的异常类型如果有父子类关系,则要求子类在上父类在下,从小到大的排序,否则报错。
*
* 5.常用的异常处理方式:1)String e.getMessage() 2)void e.printStackTrace() 这个比较常用
*
* 6.在try结构中定义的变量,出了try结构以后就不能使用了。想要使用把变量声明在外面,赋值在结构里面。
*
* 7.为什么不写成int num;而要多赋值个0,首先因为变量想要输出首先要声明好后并且有初始化的值,而局部变量
* 没有默认值,一旦try中的程序报错,直接输出num,num没有值程序会报错,为了避免这种情况,加上0不会影响程
* 序也不会因为异常情况导致num没有值而保错。
*
*8.try-catch-finally也可以嵌套
* 体会1:使用try-catch-finally结构处理编译异常时,使得编译时不会报错,但运行时有可能报错,相当于try-catch-finally
* 将编译时可能出现的异常延迟到运行时出现。
* 体会2:开发中,由于运行时异常比较常见,所以我们通常就不针对运行时异常编写try-catch-finally了。
* 针对于编译时异常,我们说一定要考虑异常的处理。(如果与前端页面交互提示时,仍要处理。)
*/
public class Demo05 {
public static void main(String[] args) {
String str="123";
str="abc";
/*为什么不写成int num;而要多赋值个0,首先因为变量想要输出首先要声明好后并且有初始化的值,
而局部变量没有默认值,一旦try中的程序报错,直接输出num,num没有值程序会报错,为了避免这种
情况,加上0不会影响程序也不会因为异常情况导致num没有值而报错。*/
int num = 0;
try {
num=Integer.parseInt(str);
//int num=Integer.parseInt(str);//出现异常
System.out.println("hell0-------01");//不会输出
} catch (NullPointerException e) {
//习惯上异常名叫 e
System.out.println("出现了空指针转换异常");
}catch (NumberFormatException e) {
//一个类型e只在一个catch中有效,所以不同的catch中名字可以相同。
//System.out.println("出现了数值转换异常"); 一般不这样写,用异常类方法代替,如下:
//String e.getMessage():此方法返回值是String类型,想要看就要输出它。因为有返回值就要定义变量进行接收,查看就要输出,这里简写一块了。
// System.out.println(e.getMessage()); //打印异常信息
//void e.printStackTrace():此方法返回值是void类型,不需要在进行输出就能查看。
e.printStackTrace(); //打印异常详细信息
}catch (Exception e){
System.out.println("出现了异常");//不会输出
}
//System.out.println(num);报错不能调用,因为变量num在catch中定义的,作用域在catch中。
System.out.println(num);
System.out.println("hell0-------02");//会输出
}
}
6.7.2 テスト 2: 最後に使用シナリオ分析
package com.atguigu.java1;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.junit.Test;
/*
* try-catch-finally中finally的使用:
*
*
* 1.finally是可选的
*
* 2.finally中声明的是一定会被执行的代码。即使catch中又出现异常了,try中有return语句,catch中有
* return语句等情况。
*
* 3.像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动的回收的,我们需要自己手动的进行资源的
* 释放。此时的资源释放,就需要声明在finally中。
*
*
*
*/
public class FinallyTest {
@Test
public void test2(){
FileInputStream fis = null;
try {
File file = new File("hello1.txt");
fis = new FileInputStream(file);
int data = fis.read();
while(data != -1){
System.out.print((char)data);
data = fis.read();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
if(fis != null)//如果文件没有创建成功为赋的默认值null会报空指针异常,加上if判断避免这一情况。
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Test
public void testMethod(){
int num = method();
System.out.println(num);
}
public int method(){
try{
int[] arr = new int[10];
System.out.println(arr[10]);
return 1;
}catch(ArrayIndexOutOfBoundsException e){
e.printStackTrace();
return 2;
}finally{
System.out.println("我一定会被执行");
return 3;
}
}
@Test
public void test1(){
try{
int a = 10;
int b = 0;
System.out.println(a / b);
}catch(ArithmeticException e){
e.printStackTrace();
// int[] arr = new int[10];
// System.out.println(arr[10]);
}catch(Exception e){
e.printStackTrace();
}
// System.out.println("我好帅啊!!!~~");
finally{
System.out.println("我好帅啊~~");
}
}
}
ショートカット キー: エラー パッケージのコードを選択します—>Sround With—>Try/catch Block
注: 最終的にストリームを閉じるようにコードを変更します。
6.8 例外処理方法 2: (スロー)
-
使用背景:
try...catch... を通じて例外を処理できますが、すべての状況で例外を処理できるわけではありません。つまり、発生する可能性のある例外を処理できない場合があります。どうすればよいでしょうか?
この状況に対して、Java はスロー処理ソリューションを提供します。 -
フォーマット:
throws 异常类名;
-
注: この形式の後には
方法的括号
、 -
コンパイル時例外は処理する必要があります。処理オプションは 2 つあります: try...catch または throws。throws オプションを使用すると、それを呼び出した人が将来それを処理します。
-
実行時例外を処理する必要はないため、問題が発生した後は、戻ってコードを変更する必要があります。
-
実行プロセス:
- メソッドの宣言には「throws + 例外の型」を記述します。このメソッドの実行時にスローされる可能性のある例外のタイプを示します。
- メソッド本体の実行時に例外が発生すると、例外コードの部分には例外クラスのオブジェクトが生成され、このオブジェクトがスロー後に例外の型に該当するとスローされます。
异常代码后续的代码,就不再执行!
6.8.1 ケース 1: throws キーワードのテスト
package com.atguigu.java1;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
* 异常处理的方式二:throws + 异常类型
*
* 1. "throws + 异常类型"写在方法的声明处。指明此方法执行时,可能会抛出的异常类型。
* 一旦当方法体执行时,出现异常,仍会在异常代码处生成一个异常类的对象,此对象满足throws后异常
* 类型时,就会被抛出。异常代码后续的代码,就不再执行!
*
* 2. 体会:try-catch-finally:真正的将异常给处理掉了。
* throws的方式只是将异常抛给了方法的调用者。 并没有真正将异常处理掉。
*
* 3. 开发中如何选择使用try-catch-finally 还是使用throws?
* 3.1 如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果
* 子类重写的方法中有异常,必须使用try-catch-finally方式处理。
* 3.2 执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。我们建议这几个方法使用throws
* 的方式进行处理。而执行的方法a可以考虑使用try-catch-finally方式进行处理。
*
*/
public class ExceptionTest2 {
public static void main(String[] args){
try{
method2();
}catch(IOException e){
e.printStackTrace();
}
// method3();
}
public static void method3(){
try {
method2();
} catch (IOException e) {
//IOException 是FileNotFoundException异常的父类,这里处理方式又相同所以只需要写一个catch即可。
e.printStackTrace();
}
}
//method1抛出了2个异常,这里method2调用为什么只抛出一个异常呢??
//如果2个异常是父子类关系,并且处理异常的方式相同,比如都是e.printStackTrace();,那么只需要抛出一个异常即可。
public static void method2() throws IOException{
method1();
}
public static void method1() throws FileNotFoundException,IOException{
File file = new File("hello1.txt");
FileInputStream fis = new FileInputStream(file);
int data = fis.read();
while(data != -1){
System.out.print((char)data);
data = fis.read();
}
fis.close();
System.out.println("hahaha!");
}
}
6.8.2 ケース 2: サブクラスで書き換えられたテスト メソッドが親クラスよりも小さい例外をスローする
メソッドのオーバーライドに関する規則の 1 つは、サブクラスのオーバーライドされたメソッドによってスローされる例外のタイプが、親クラスのオーバーライドされたメソッドによってスローされる例外のタイプより大きくないことです。
package com.atguigu.java1;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
* 方法重写的规则之一:
* 子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
*
*
*/
public class OverrideTest {
public static void main(String[] args) {
OverrideTest test = new OverrideTest();
test.display(new SubClass());
}
public void display(SuperClass s){
try {
s.method();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class SuperClass{
public void method() throws IOException{
}
}
class SubClass extends SuperClass{
//如果方法重写调用子类的方法的方法体,子类抛出的异常大于父类的,父类已经处理的异常在子类中不包含,则父类处理异常没有什么意义。
public void method()throws FileNotFoundException{
}
}
6.9 例外オブジェクトを手動でスローする (throw)
-
以下に示すように、 background : を使用します。
-
機能: メソッド本体内で例外オブジェクトをスローするために使用されます。
-
例外オブジェクトの生成について:
- システムによって自動的に生成される例外オブジェクト
- 例外オブジェクトを手動で生成してスローする
-
注意: 例外が手動でスローされた場合、それが実行時例外オブジェクトの場合は処理する必要はありませんが、コンパイル時例外オブジェクトの場合は例外を処理する必要があります。
6.9.1 手動で例外オブジェクトをスローする前に
package com.atguigu.java2;
public class StudentTest {
public static void main(String[] args) {
Student s = new Student();
s.regist(-1001);
System.out.println(s);//直接输出对象的引用实际上时输出.toString()方法。
}
}
class Student{
private int id;
public void regist(int id) {
if(id > 0){
this.id = id;
}else{
/*
* 即便你此时输入的是负数不合理,只能给你个提示输入的数据错误,但是这样写还是把结果输出了。
* 正常来讲:应该是输入的是负数不合理,程序直接报错不会再向下执行输出结果,所以这里一般是手动抛出异常对象,
* 一旦数据不合理直接报异常,程序停止运行。
*/
System.out.println("您输入的数据非法!");
}
}
@Override
public String toString() {
return "Student [id=" + id + "]";
}
}
6.9.2 手動で例外オブジェクトをスローした後
package com.atguigu.java2;
public class StudentTest {
public static void main(String[] args) {
try {
Student s = new Student();
s.regist(-1001);
System.out.println(s);
} catch (Exception e) {
// e.printStackTrace();
/*throw new RuntimeException("您输入的数据非法!")里面的值是由RuntimeException的有参构造方法中super(xxx)调用--->
* 父类的Exception的有参构造方法中super(xxx)调用----> Throable中的有参构造方法,在Throable类中通过有参构造方法
* 赋值(this.detailMessage = message;) 给成员变量: private String detailMessage;为:您输入的数据非法!
* 即:值最终赋值给Throable类的成员变量detailMessage。
*
* void e.getMessage() 底层源码:
* public String getMessage() {
* return detailMessage;
* }
* 这个方法getMessage()的返回值为Throable类中的detailMessage成员变量,所以输出结果为:您输入的数据非法! */
System.out.println(e.getMessage());
}
}
}
class Student{
private int id;
public void regist(int id) throws Exception {
if(id > 0){
this.id = id;
}else{
// System.out.println("您输入的数据非法!");
//手动抛出异常对象
// throw new RuntimeException("您输入的数据非法!");抛出运行时异常,调用方不用处理。
// throw new Exception("您输入的数据非法!");Exception包含编译器异常,所以一旦throws抛出,在调用方一定要进行处理编译器异常。
throw new MyException("不能输入负数");//抛出的是自定义异常
//错误的 String不是异常类
// throw new String("不能输入负数");
//return 0;如果方法有返回值且不影响结果,则可以用throw代替return,因为如果报异常也会结束方法运行。
}
}
@Override
public String toString() {
return "Student [id=" + id + "]";
}
}
6.9.3 スローとスローの違い
6.10 カスタム例外
背景を使用する:
- その目的は、システムによって提供される例外タイプは、
有限的
プログラムによって生成された例外が提供されない場合に、独自に定義した例外をスローして例外タイプを作成できることです更加精确
(通常は throw と組み合わせて使用されます)。 - 通常、このカスタム例外クラスは、
定义这个类时要做到见名知意
です。
形式:
例:
6.10.1 テスト
ケース 6.9.2 と組み合わせて使用されます。
package com.atguigu.java2;
/*
* 如何自定义异常类?
* 1.继承于现有的异常结构:RuntimeException 、Exception(包含运行和编译器异常,
* 所以编译期就要进行处理异常)
* RuntimeException异常:只需要继承RuntimeException异常或者它的子类。
* Checked异常:只需要继承Exception异常或者Exception的子类,但需要除RuntimeException之外。
* 2.提供全局常量:serialVersionUID
* 3.提供重载的构造器
*
*/
public class MyException extends Exception{
static final long serialVersionUID = -7034897193246939L;
//无参构造方法
public MyException(){
}
//有参构造方法
public MyException(String msg){
/*
* 调用父类的有参构造,因为上面的案例中处理异常使用的是e.getMessage()方法,
* 这个方法返回值为Throable的成员变量dtailMessage属性。而现在自定义异常对象
* 的通过有参构造方法创建对象并传参,这个自定义异常对象的参数不是自己定义的而是定义
* 在顶级父类Throable中的成员变量,所以想要赋值给父类Throable的属性需要在子类
* 的构造方法中通过super一步一步调用父类构造方法,最终在Throwable的构造方法中把
* 值赋值给成员变量dtailMessage。
*/
super(msg);
}
}
7. 内部クラス
7.1 メンバー内部クラス (静的/非静的)
package com.atguigu.java2;
/*
* 类的内部成员之五:内部类
* 1. Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类
*
* 2.内部类的分类:成员内部类(静态、非静态) vs 局部内部类(方法内、代码块内、构造器内)
*
* 3.成员内部类:
* 一方面,作为外部类的成员:
* >调用外部类的结构
* >可以被static修饰
* >可以被4种不同的权限修饰
*
* 另一方面,作为一个类:
* > 类内可以定义属性、方法、构造器等
* > 可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承
* > 可以被abstract修饰
*
*
* 4.关注如下的3个问题
* 4.1 如何实例化成员内部类的对象
* 4.2 如何在成员内部类中区分调用外部类的结构
* 4.3 开发中局部内部类的使用 见《InnerClassTest1.java》
*
*/
public class InnerClassTest {
public static void main(String[] args) {
//创建Dog实例(静态的成员内部类):
Person.Dog dog = new Person.Dog();
dog.show();
//创建Bird实例(非静态的成员内部类):
// Person.Bird bird = new Person.Bird();//错误的
Person p = new Person();
Person.Bird bird = p.new Bird();
bird.sing();
System.out.println();
bird.display("黄鹂");
}
}
class Person{
//外部类
String name = "小明";
int age;
public void eat(){
System.out.println("人:吃饭");
}
//静态成员内部类
static class Dog{
String name;
int age;
public void show(){
System.out.println("卡拉是条狗");
// eat();
}
}
//非静态成员内部类
class Bird{
String name = "杜鹃";
public Bird(){
}
public void sing(){
System.out.println("我是一只小小鸟");
Person.this.eat();//调用外部类的非静态属性 属性不同名可以省略为:eat();
eat();
System.out.println(age);
}
public void display(String name){
System.out.println(name);//方法的形参
System.out.println(this.name);//内部类的属性
System.out.println(Person.this.name);//外部类的属性 属性不同名可以省略
}
}
public void method(){
//局部内部类
class AA{
}
}
{
//局部内部类
class BB{
}
}
public Person(){
//局部内部类
class CC{
}
}
}
7.2 ローカル内部クラス (匿名/非匿名)
package com.atguigu.java2;
public class InnerClassTest1 {
//开发中很少见
public void method(){
//局部内部类
class AA{
}
}
//返回一个实现了Comparable接口的类的对象
public Comparable getComparable(){
//创建一个实现了Comparable接口的类:局部内部类
//方式一:
// class MyComparable implements Comparable{ //Comparable为源码里面的接口
//
// @Override
// public int compareTo(Object o) {
// return 0;
// }
//
// }
//
// return new MyComparable();
//方式二:
return new Comparable(){
@Override
public int compareTo(Object o) {
return 0;
}
};
}
}