2023 最新バージョンの JavaSE チュートリアル - 6 日目: オブジェクト指向プログラミング (基礎)

目次

1. オブジェクト指向プログラミングの概要(理解)

1.1 プログラミングの考え方

オブジェクト指向は、ソフトウェア開発におけるプログラミング スタイルおよび開発パラダイムです。 面向对象 の他に、面向过程指令式编程函数式编程 もあります。すべてのプログラミング パラダイムの中で、私たちが最もよく知っているのは、プロセス指向とオブジェクト指向の 2 つです。例え: 歴史書の種類

  • 伝記スタイル: 伝記を中心とし、本纪 皇帝の説明、世家 王子、封建国家、特別な人物の説明、列传 民間の人物について説明します。
  • 年表形式:年、月、日の順に記載されます。
  • 国家形式: 特定の国の出来事を記録し、多くの国の歴史を記録する歴史散文です。

初期にはプロセス指向の考え方がありましたが、ソフトウェアの規模が拡大し、問題が複雑になるにつれて、 プロセス指向弊端がますます明白になってきました。という考え方が生まれ、現在の主流となったのです。

1. プロセス指向プログラミング ( と呼ばれます)POP

  • 焦点は 过程 です。プロセスとは、データを操作する手順です。特定のプロセスの実装コードが繰り返し出現する場合、そのプロセスを 函数 に抽出できます。これにより、冗長コードが大幅に簡素化され、メンテナンスが容易になります。
  • 代表的な言語:C言語
  • コード構造: 函数 は組織単位です。
  • 执行者思维 の一種で、単純な問題を解決するのに適しています。スケーラビリティが低く、後のメンテナンスが困難です。

2. オブジェクト指向プログラミング、 と呼ばれますOOP

  • 注目すべき点は です。コンピュータ プログラミングのプロセスでは、現実の物事を参照して、物事の属性や動作特性が抽象化され、クラスによって表現されます。
  • 代表的な言語: Java、C#、C++、Python、Ruby、PHP など。
  • コード構造: は組織単位です。それぞれのものには独自の 属性行为/功能 があります。
  • 设计者思维 の一種で、複雑な問題を解決するのに適しています。コードは拡張性と保守性が高くなります。

1.2 実際の問題に基づいてプログラムを設計する方法

考察1:どうやって運転するの?

プロセス指向で問題を考えるときは、まず 怎么按步骤实现? 考え、ステップを段階的にメソッドにマッピングし、最終的にそれを完了します。これは 简单任务 に適していますが、 过多协作 は必要ありません。実行方法については、次の手順をリストできます。
ここに画像の説明を挿入します
プロセス指向は、実行方法に重点を置き、共同作業を必要としない単純なものに適しています。

考察2: 車はどうやって作るの?

車の組み立ては非常に複雑で、完了するには 很多协作 が必要です。現時点では、具体的な手順に従って車を組み立てる方法ではなく、 车怎么设计? について考えています。これは考え方の変化であり、前者はオブジェクト指向思考です。したがって、オブジェクト指向 (オブジェクト指向) の思考は、人間の思考パターンにより一致しています。オブジェクト指向の考え方を使用して車を設計する方法を考えます:
ここに画像の説明を挿入します
当然のことながら、車が何でできているかについて考え始めます。車は次の構造で構成されていることがわかりました。
ここに画像の説明を挿入します
タイヤの製造工程を完了するタイヤ工場と、エンジンの製造工程を完了するエンジン工場が見つかりました。このようにして、全員が同時に自動車を製造し、最終的に組み立てることができるため、効率が大幅に向上します。しかし、タイヤ工場の流れ作業となると、やはり工程があり、プロセス重視の考え方が欠かせません!したがって、オブジェクト指向は、マクロの観点からシステム全体を把握し、分析するのに役立ちます。 ただし、実装部分 (つまり、各メソッド) に固有のマイクロ操作は、依然としてプロセス指向のアプローチで処理する必要があります。

注: プロセス指向とオブジェクト指向を対比してはなりません。それらは互いに補完し合います。オブジェクト指向はプロセス指向から切り離すことはできません。

類推例 1:
ここに画像の説明を挿入します
需要が単一または単純な場合、問題なく段階的に処理でき、効率は非常に高くなります。しかし、ニーズが変化し、機能が増加するにつれて、各ステップに対応するのは非常に面倒であることがわかり、これらのステップと機能をカプセル化できないか考え始めました。 、同様の機能を持つ関数がパッケージ化されています。 これにより、構造がより明確になります。使用するときは、対応するクラスを見つけるだけです。これがオブジェクト指向の考え方です。

類推例 2: 男性が象を冷蔵庫に入れる - プロセスは次のとおりです:

1.打开冰箱
2.把大象装进冰箱
3.把冰箱门关住

オブジェクトは次のとおりです。

人{
    打开(冰箱){
		冰箱.开门();	
    }
    操作(大象){
             大象.进入(冰箱);
    }
    关闭(冰箱){   
          冰箱.关门();     
    }
}

冰箱{
     开门(){ }  
     关门(){ }
}

大象{
     进入(冰箱){  }
}

演習: 以下のシステム内のクラスとその関係を抽象化します
ここに画像の説明を挿入します

1.3 このアイデアをマスターするにはどうすればよいですか?

ここに画像の説明を挿入します

2. Java 言語の基本要素: クラスとオブジェクト

2.1 はじめに

人々の世界理解は実際にはオブジェクト指向です。たとえば、人魚(見たことのない人魚)について知りましょう。
ここに画像の説明を挿入します
注意深く研究した結果、人魚には通常、いくつかの特徴があることがわかりました。

女孩
有鱼尾
美丽

要約のプロセスは、実際には 抽象化 のプロセスです。人魚の抽象的な特徴は 1 つの美人鱼类に要約できます。この図にあるものはすべて、このクラス 具体的对象 によって表現されます。

2.2 クラスとオブジェクトの概要

类(Class)对象(Object) はオブジェクト指向の中核概念です。

1. クラスとは何ですか?

クラス: 同じ特性を持つものの抽象的な説明、抽象的、概念的な定義。

2. オブジェクトとは何ですか?

オブジェクト: 実際に存在するこの種の物の 每个个体具体的 であるため、とも呼ばれます。 a>实例(instance)
ここに画像の説明を挿入します
は次のように理解できます: 类 => 抽象概念的人;对象 => 实实在在的某个人
ここに画像の説明を挿入します
ここに画像の説明を挿入します

3. クラスとオブジェクトの関係の誤解

曰:"白马非马,可乎?"
曰:"可。"
曰:"何哉?"
曰:"马者,所以命形也。白者,所以命色也。命色者,非命形也,故曰白马非马。"

ここに画像の説明を挿入します

2.3 クラスメンバーの概要

オブジェクト指向プログラミングの焦点は 类的设计
クラスの設計であり、実際には 类的成员的设计

クジラからアリに至るまで、現実世界の生物はすべて最も基本的なものでできています细胞。同様に、Java コードの世界は、さまざまな機能を持つ多数の で構成されています。
ここに画像の説明を挿入します
実際の生物世界の細胞は何でできていますか?核、細胞質など... Java でクラスを使用して物事を記述する場合にも同じことが当てはまります。クラスは、関連する 属性行为 のセットであり、これらはクラスの 2 つの最も基本的なメンバーでもあります。

  • 属性: このタイプのステータス情報。対応するクラスの 成员变量
    • メンバー変数 <=> プロパティ <=> フィールド
  • 動作: このタイプのモノが行うべき操作、またはモノの状態に基づいて何ができるか。対応するクラスの 成员方法
    • (メンバー) メソッド <=> 関数 <=> メソッド

ここに画像の説明を挿入します
例:
ここに画像の説明を挿入します

2.4 オブジェクト指向機能を完成させるための 3 つのステップ (重要)

2.4.1 ステップ 1: クラス定義

クラスの定義では、キーワード class を使用します。形式は次のとおりです。

[修饰符] class 类名{
    
    
	属性声明;
    方法声明;
}

例 1:

public class Person{
    
    
    //声明属性age
    int age ;	                   
    
    //声明方法showAge()
    public void eat() {
    
            
	    System.out.println("人吃饭");
    }
}

例 2:

public class Dog{
    
    
    //声明属性
	String type; //种类
	String nickName; //昵称
	String hostName; //主人名称
	
    //声明方法
	public void eat(){
    
     //吃东西
		System.out.println("狗狗进食");		
	}
}

例 3:

public class Person{
    
    
    String name;
    char gender;
    Dog dog;
    
    //喂宠物
    public void feed(){
    
    
        dog.eat();
    }
}

2.4.2 ステップ 2: オブジェクトの作成

ここに画像の説明を挿入します
オブジェクトを作成し、キーワードを使用します: new
オブジェクトを作成する構文:

//方式1:给创建的对象命名
//把创建的对象用一个引用数据类型的变量保存起来,这样就可以反复使用这个对象了
类名 对象名 = new 类名();

//方式2:
new 类名()//也称为匿名对象

例:

class PersonTest{
    
    
	public static void main(String[] args){
    
    
		//创建Person类的对象
		Person per = new Person();
		//创建Dog类的对象
		Dog dog = new Dog();
	}
}

2.4.3 ステップ 3: オブジェクトがプロパティまたはメソッドを呼び出す

オブジェクトはクラス のインスタンスであり、そのタイプの属性と動作 (メソッドなど) を持っている必要があります。 または を使用して、オブジェクト メンバー (プロパティやメソッドを含む) にアクセスします。对象名.属性对象名.方法

例 1:

//声明Animal类
public class Animal {
    
     //动物类
    public int legs;

    public void eat() {
    
    
        System.out.println("Eating.");
    }

    public void move() {
    
    
        System.out.println("Move.");
    }
}
//声明测试类
public class AnimalTest {
    
    
    public static void main(String args[]) {
    
    
        //创建对象
        Animal xb = new Animal();
        xb.legs = 4;//访问属性
        System.out.println(xb.legs);
        xb.eat();//访问方法
        xb.move();//访问方法
    }
}

図の理解:
ここに画像の説明を挿入します
例 2: 前のステップ 1 の例 2: クラスのインスタンス化 (クラスのオブジェクトの作成)

public class Game{
    
    
    public static void main(String[] args){
    
    
        Person p = new Person();
        //通过Person对象调用属性
        p.name = "康师傅";
        p.gender = '男';
        p.dog = new Dog(); //给Person对象的dog属性赋值
        
        //给Person对象的dog属性的type、nickname属性赋值
        p.dog.type = "柯基犬";
        p.dog.nickName = "小白";
        
        //通过Person对象调用方法
        p.feed();
    }
}

2.5 匿名オブジェクト

オブジェクトのハンドルを定義せずに、このオブジェクトのメソッドを直接呼び出すこともできます。このようなオブジェクトは匿名オブジェクトと呼ばれます。例: new Person().shout(); 使用法:

  • オブジェクトがメソッド呼び出しを 1 つだけ必要とする場合は、匿名オブジェクトを使用できます。
  • メソッド呼び出しの引数として匿名オブジェクトを渡すことがよくあります。

3. オブジェクトのメモリ解析

3.1 JVMのメモリ構造分割

HotSpot Java 仮想マシンのアーキテクチャ図は次のとおりです。その中で私たちが主に関心を持っているのは、実行時データ領域 (Runtime Data Area) です。
ここに画像の説明を挿入します
その中には次のようなものがあります: 堆(Heap): このメモリ領域の唯一の目的はオブジェクト インスタンスを保存することであり、ほとんどすべてのオブジェクト インスタンスがここにメモリを割り当てます。これについては、Java 仮想マシン仕様で説明されています。すべてのオブジェクト インスタンスと配列はヒープ上に割り当てる必要があります。 栈(Stack): 仮想マシン スタックを指します。仮想マシン スタックは、ローカル変数などを保存するために使用されます。ローカル変数テーブルには、さまざまな基本データ型 (boolean、byte、char、short、int、float、long、double) とオブジェクト参照 (参照型。オブジェクト自体とは等価ではありませんが、ヒープ内のオブジェクトです) が格納されます。その長さはコンパイル時に知ることができます (メモリの最初のアドレス)。メソッドが実行されると、メソッドは自動的に解放されます。 方法区(Method Area): 仮想マシンによってロードされたクラス情報、定数、静的変数、ジャストインタイム コンパイラによってコンパイルされたコードなどのデータを保存するために使用されます。

3.2 オブジェクトメモリの解析

例:

class Person {
    
     //类:人
    String name;
    int age;
    boolean isMale;
}

public class PersonTest {
    
     //测试类
    public static void main(String[] args) {
    
    
        Person p1 = new Person();
        p1.name = "赵同学";
        p1.age = 20;
        p1.isMale = true;

        Person p2 = new Person();
        p2.age = 10;

        Person p3 = p1;
        p3.name = "郭同学";
    }
}

メモリ分析図:
ここに画像の説明を挿入します
説明: ヒープ: new によって生成されたすべての構造 (オブジェクト、配列) はヒープ領域に配置されます。オブジェクトのプロパティはヒープ領域に保存されます。クラスの複数のオブジェクト (p1、p2 など) を作成すると、各オブジェクトには現在のクラスのセットが含まれます 副本(即属性) 1 つのオブジェクトを通じてプロパティを変更しても、他のオブジェクトのこのプロパティの値には影響しません。割り当てに既存のオブジェクトを使用して新しい変数を宣言する場合 (p3 = p1 など)、ヒープ領域に新しいオブジェクトは作成されません。代わりに、2 つの変数はヒープ領域内の同じオブジェクトを共同で指します。 1 つのオブジェクトを通じてプロパティが変更されると、別のオブジェクトのこのプロパティへの呼び出しに影響します。

インタビューの質問: オブジェクト名には何が格納されますか? 答え: オブジェクト アドレス

public class StudentTest{
    
    
    public static void main(String[] args){
    
    
        System.out.println(new Student());//Student@7852e922

        Student stu = new Student();
        System.out.println(stu);//Student@4e25154f
        
        int[] arr = new int[5];
		System.out.println(arr);//[I@70dea4e
    }
}

オブジェクト名と配列名を直接出力すると、类型@对象的hashCode值 と表示されるため、 クラスと配列は参照データになります。 type、データ型を参照する変数は、オブジェクトのアドレスを格納するか、ヒープ内のオブジェクトの最初のアドレスを指します。
ここに画像の説明を挿入します

3.3 演習

コードに従って、メモリ マップを描画します。

class Car {
    
    
    String color = "red";
    int num = 4;

    void show() {
    
    
        System.out.println("color=" + color + ",num=" + num);
    }
}

class CarTest {
    
    
    public static void main(String[] args) {
    
    
        Car c1 = new Car();   //建立对象c1
        Car c2 = new Car();   //建立对象c2
        c1.color = "blue";   //对对象的属性进行修改
        c1.show();   //使用对象的方法
        c2.show();
    }
}

4. クラスのメンバーの 1 つ: メンバー変数 (フィールド)

4.1 メンバ変数の宣言方法

構文形式:

[修饰符1] class 类名{
    
    
    [修饰符2] 数据类型 成员变量名 [= 初始化值]; 
}
  • 例証します:
    • 位置要件: クラス内、メソッド外にある必要があります
    • 修飾子 2 (まだ検討されていません)
      • 一般的に使用される権限修飾子は、private、default、protected、public です。
      • その他の修飾子: static、final
    • データの種類
      • 任意の基本データ型 (int、Boolean など) または任意の参照データ型。
    • メンバー変数名
      • これは識別子であり、命名規則と仕様に準拠する必要があります。
    • 初期化値
      • 状況に応じて、値を明示的に割り当てることもできますが、値を割り当てずにデフォルト値を使用することもできます。

例:

public class Person{
    
    
	private int age;             //声明private变量 age
	public String name =Lila;    //声明public变量 name
}

4.2 メンバー変数とローカル変数

1. 変数の分類: メンバー変数とローカル変数

  • メソッドの外およびクラス内で宣言された変数はメンバー変数と呼ばれます。
  • メソッド本体内で宣言された変数はローカル変数と呼ばれます。

ここに画像の説明を挿入します
ここに画像の説明を挿入します
このうち、static はメンバー変数を静的変数と非静的変数の 2 つのカテゴリに分類できます。静的変数はクラス変数とも呼ばれ、非静的変数はインスタンス変数または属性とも呼ばれます。次に、インスタンス変数について学びましょう。

2. メンバ変数とローカル変数の比較

  • 同じ点

    • 変数宣言の形式は同じです: データ型変数名 = 初期化値
    • 変数は最初に宣言し、次に初期化してから使用する必要があります。
    • 変数には対応するスコープがあります。その範囲内でのみ有効です
  • 違い

  1. どこでどのように宣言するか

    • インスタンス変数: クラス内の外部メソッド
    • ローカル変数: メソッド本体 {} 内、またはメソッドの仮パラメータ リストまたはコード ブロック内
  2. メモリ内の異なる場所に保存される

    • インスタンス変数: ヒープ
    • ローカル変数: スタック
  3. ライフサイクル

    • インスタンス変数: オブジェクトのライフサイクルと同様に、インスタンス変数はオブジェクトの作成時に存在し、オブジェクトが GC によってリサイクルされるときに消滅します。また、各オブジェクトのインスタンス変数は独立しています。
    • ローカル変数: メソッド呼び出しのライフサイクルと同様に、ローカル変数はメソッドが呼び出されるたびに存在し、メソッドの実行が終了すると消滅します。また、各メソッド呼び出しは独立しています。
  4. 範囲

    • インスタンス変数: オブジェクトを通じて使用でき、このクラスで直接呼び出されます。他のクラスでは「object.instance 変数」
    • ローカル変数: スコープ外では使用できません
  5. 修飾子 (後述)

    • 实例变量:public,protected,private,final,volatile,transient
    • ローカル変数: 最終
  6. デフォルト値

    • インスタンス変数: デフォルト値があります
    • ローカル変数: なし。手動で初期化する必要があります。仮パラメータは特別であり、実パラメータによって初期化されます。

3. オブジェクト属性のデフォルトの初期化割り当て

オブジェクトが作成されると、さまざまなタイプのメンバー変数が自動的に初期化され、値が割り当てられます。
ここに画像の説明を挿入します
4. 例

class Person {
    
    //人类
    //1.属性
    String name;//姓名
    int age = 1;//年龄
    boolean isMale;//是否是男性

    public void show(String nation) {
    
    
        //nation:局部变量
        String color;//color:局部变量
        color = "yellow";
    }
}

//测试类
class PersonTest {
    
    
    public static void main(String[] args) {
    
    
        Person p = new Person();
        p.show("CHN");
    }
}

ここに画像の説明を挿入します

5. クラスの 2 番目のメンバー: メソッド

5.1 メソッドの紹介

ここに画像の説明を挿入します
ゲーム「ストリートファイター」では、キャラクターがパンチ、キック、ジャンプするたびに 50 ~ 80 行のコードを記述する必要があり、キャラクターがパンチ、キック、ジャンプするたびにそれを繰り返す必要があります。この 50 ~ 80 行のコードを記述すると、 很臃肿 となり、可読性が非常に低くなります。コードを繰り返し記述する問題を解決するには、パンチ、キック、またはジャンプのコードを抽出して {} に入れ、このコードに名前を付けます。これにより、パンチ、キック、またはジャンプするたびに、この名前による {} のコード。上記の処理において、抽出されたコードはプログラム内で定義されたメソッドとみなすことができ、プログラムはパンチ、キック、ジャンプが必要なときにこのメソッドを呼び出すことができます。

5.2 メソッド(メソッド、関数)の理解

方法 は、クラスまたはオブジェクトの動作特性を抽象化したもので、特定の機能操作を完了するために使用されます。言語によっては 函数 または 过程 とも呼ばれます。機能をメソッドにカプセル化する目的は、 实现代码重用,减少冗余,简化代码できるようにすることです。 Java のメソッド 不能独立存在、すべてのメソッドはクラス内で定義する必要があります。例 1:

  • Math.random() の random() メソッド
  • Math.sqrt(x) の sqrt(x) メソッド
  • System.out.println(x) の println(x) メソッド
  • new Scanner(System.in).nextInt() の nextInt() メソッド
  • Arrays クラスの binarySearch() メソッド、sort() メソッド、equals() メソッド

例 2:

public class Person{
    
    
    private int age;
    public int getAge()  {
    
      //声明方法getAge()
		return age; 
    }
    public void setAge(int i) {
    
      //声明方法setAge
		age = i;        //将参数i的值赋给类的成员变量age
    }
}  

5.3 メソッドの宣言方法

1. メソッド宣言の構文形式

[修饰符] 返回值类型 方法名([形参列表])[throws 异常列表]{
    
    
        方法体的功能代码
}

(1) 完全なメソッド = メソッド ヘッダー + メソッド本体。

  • メソッド ヘッダーは [修饰符] 返回值类型 方法名([形参列表])[throws 异常列表] であり、 方法签名 とも呼ばれます。通常、メソッドを呼び出すときはメソッドヘッダーに注目するだけで、メソッドヘッダーからメソッドの機能や呼び出し形式がわかります。
  • メソッド本体は、メソッドが呼び出された後に実行されるコードです。呼び出し元にとって、メソッド本体の実装方法を理解していなくても、メソッドの使用には影響しません。

(2) メソッドヘッダーには 5 つの部分が含まれる場合があります

  • 修飾子: オプション。メソッドには、public、protected、private、static、abstract、native、final、synchronized などの修飾子も多数あります。後で 1 つずつ学習します。

    • このうち、権限修飾子は、public、protected、および private です。カプセル化について話す前に、まずデフォルトで歯髄修正方法を使用します。
    • このうちメソッドは、静的かどうかによって静的メソッドと非静的メソッドに分けられます。静的メソッドはクラス メソッドとも呼ばれ、非静的メソッドはインスタンス メソッドとも呼ばれます。静的について話す前に、まずインスタンス メソッドについて学びましょう。
  • 戻り値の型: メソッドの実行結果を表すデータ型。結果はメソッドの実行後に呼び出し元に返されます。

    • 戻り値がない場合は、 void を宣言します。
    • に戻り値がある場合は、戻り値の型を宣言します (任意の型を指定できます)。メソッド本体の return 返回值 とともに使用されます。
  • メソッド名: 識別子に属します。名前を付けるときは、識別子の命名規則と仕様に従ってください。意味を知るには名前を参照してください。

  • 仮パラメータ リスト: メソッド本体の機能を完了するために外部から提供されるデータのリストを示します。ゼロ、または 1 つ以上のパラメーターを含めることができます。

    • パラメータの有無に関わらず()は省略できません
    • パラメータがある場合は、各パラメータでデータ型とパラメータ名を指定する必要があります。複数のパラメータを区切るには、次のようにカンマを使用します。
      • 1 つのパラメータ: (データ型パラメータ名)
      • 2 つのパラメータ: (データ タイプ 1 パラメータ 1、データ タイプ 2 パラメータ 2)
    • パラメータのタイプは、基本データ型または参照データ型です。
  • スロー例外リスト: オプション。後続の章で説明します

(3) メソッド本体: メソッド本体は{}で囲み、{}内にメソッド関数を完成させるコードを記述します。

(4) メソッド本体の return 文の説明:

  • return ステートメントの機能は、メソッドの実行を終了し、メソッドの結果を返すことです。
  • 戻り値の型が void でない場合は、メソッド本体に return 返回值; ステートメントが必要であり、戻り値の結果の型は、宣言された戻り値の型。
  • 戻り値の型が void の場合、メソッド本体に return ステートメントを使用する必要はありません。return ステートメントを使用してメソッドの実行を早期に終了する場合は、return ステートメントの後に return ステートメントを続けることはできません。戻り値を直接書き込むreturn; 以上です。 return ステートメントの後に他のコードを記述することはできません。それ以外の場合は、「到達不能コード」というエラーが報告されます。

補足: メソッドは、仮パラメータと戻り値の有無によって分類されます
ここに画像の説明を挿入します
2. 類似例
ここに画像の説明を挿入します
3. コード例:

/**
 * 方法定义案例演示
 */
public class MethodDefineDemo {
    
    
    /**
     * 无参无返回值方法的演示
     */
    public void sayHello(){
    
    
        System.out.println("hello");
    }

    /**
     * 有参无返回值方法的演示
     * @param length int 第一个参数,表示矩形的长
     * @param width int 第二个参数,表示矩形的宽
     * @param sign char 第三个参数,表示填充矩形图形的符号
     */
    public void printRectangle(int length, int width, char sign){
    
    
        for (int i = 1; i <= length ; i++) {
    
    
            for(int j=1; j <= width; j++){
    
    
                System.out.print(sign);
            }
            System.out.println();
        }
    }

    /**
     * 无参有返回值方法的演示
     * @return
     */
    public int getIntBetweenOneToHundred(){
    
    
        return (int)(Math.random()*100+1);
    }
    
    /**
     * 有参有返回值方法的演示
     * @param a int 第一个参数,要比较大小的整数之一
     * @param b int 第二个参数,要比较大小的整数之二
     * @return int 比较大小的两个整数中较大者的值
     */
    public int max(int a, int b){
    
    
        return a > b ? a : b;
    }
}

5.4 インスタンスメソッドの呼び出し方法

メソッドはメソッド名によって呼び出され、呼び出されるまで実行されません。

1. メソッド呼び出し構文形式

对象.方法名([实参列表])

2. 例

例 1:

/**
 * 方法调用案例演示
 */
public class MethodInvokeDemo {
    
    
    public static void main(String[] args) {
    
    
        //创建对象
        MethodDefineDemo md = new MethodDefineDemo();

        System.out.println("-----------------------方法调用演示-------------------------");

        //调用MethodDefineDemo类中无参无返回值的方法sayHello
        md.sayHello();
        md.sayHello();
        md.sayHello();
        //调用一次,执行一次,不调用不执行

        System.out.println("------------------------------------------------");
        //调用MethodDefineDemo类中有参无返回值的方法printRectangle
        md.printRectangle(5,10,'@');

        System.out.println("------------------------------------------------");
        //调用MethodDefineDemo类中无参有返回值的方法getIntBetweenOneToHundred
        md.getIntBetweenOneToHundred();//语法没问题,就是结果丢失

        int num = md.getIntBetweenOneToHundred();
        System.out.println("num = " + num);

        System.out.println(md.getIntBetweenOneToHundred());
        //上面的代码调用了getIntBetweenOneToHundred三次,这个方法执行了三次

        System.out.println("------------------------------------------------");
        //调用MethodDefineDemo类中有参有返回值的方法max
        md.max(3,6);//语法没问题,就是结果丢失
        
        int bigger = md.max(5,6);
        System.out.println("bigger = " + bigger);

        System.out.println("8,3中较大者是:" + md.max(8,9));
    }
}

例 2:

//1、创建Scanner的对象
Scanner input = new Scanner(System.in);//System.in默认代表键盘输入

//2、提示输入xx
System.out.print("请输入一个整数:"); //对象.非静态方法(实参列表)

//3、接收输入内容
int num = input.nextInt();  //对象.非静态方法()

5.5 使用上の注意

(1) 最初に宣言してから使用する必要があり、メソッドはクラス内で定義する必要があります
(2) 呼び出されると実行され、呼び出されないと実行されません。
(3) メソッド内でクラス内のメソッドやプロパティを呼び出すことはできますが、メソッド内にメソッドを定義することはできません。

正しい例:

{
    
    
    方法1(){
    
    
        
    }
    方法2(){
    
    
        
    }
}

エラーの例:

{
    
    
    方法1(){
    
    
        方法2(){
    
      //位置错误
        
   		}
    }
}

5.6 キーワード return の使用

  • メソッドにおける return の役割:
    • 機能 1: メソッドを終了する
    • 機能 2: メソッドを終了するときに、メソッドの呼び出し元にデータを返すことができます。
  • 注: return キーワードの直後に実行ステートメントを宣言することはできません。

5.7 メソッド呼び出しメモリの解析

  • メソッド没有被调用の場合、それらはすべてバイトコード ファイル (.class)方法区 に格納されます。

  • メソッド 被调用 を使用する場合は、 栈内存 で実行する必要があります。メソッドが呼び出されるたびに、スタック上にアクション 入栈 が発生し、現在のメソッドのローカル変数の値を保存するために現在のメソッド用に独立したメモリ領域が開きます。

  • メソッドの実行が終了すると、出栈 と呼ばれるメモリが解放されます。メソッドに戻り値がある場合は、結果が呼び出し元に返されます。戻り値の場合は、直接終了します。 、呼び出し位置に戻り、次の命令の実行を続けます。

  • スタック構造: 先入れ、後出し、後入れ、先出し。分析例:

/**
 * @author AmoXiang
 * @create 9:21
 */
public class Person {
    
    
    public static void main(String[] args) {
    
    
        Person p1 = new Person();
        p1.eat();

    }
    public static void eat() {
    
    
        sleep();
        System.out.println("人:吃饭");
    }
    public static void sleep(){
    
    
        System.out.println("人:睡觉");
        doSport();
    }
    public static void doSport(){
    
    
        System.out.println("人:运动");
    }
}

メモリ分析:
ここに画像の説明を挿入します

5.8 演習

演習 1: 次の定義を使用して Person クラスを作成します。
ここに画像の説明を挿入します
要件:

  1. Person クラスのオブジェクトを作成し、オブジェクトの名前、年齢、性別属性を設定し、study メソッドを呼び出して文字列を出力します。studying call showAge() メソッドは年齢値を表示し、addAge() メソッドを呼び出してオブジェクトの age 属性値に 2 年を追加します。
  2. 2 番目のオブジェクトを作成し、上記の操作を実行して、同じクラスの異なるオブジェクト間の関係を体験します。

演習 2: オブジェクト指向プログラミング メソッドを使用して、属性 (半径) と円の面積を計算するメソッドを含む円クラス Circle を設計します。テスト クラスを定義し、Circle クラスのオブジェクトを作成してテストします。

演習 3:

  1. プログラムを作成し、メソッドメソッドを宣言し、メソッド内で 10*8的*型矩形 を出力し、メイン メソッド内でメソッドを呼び出します。
  2. 前のプログラムを修正します。メソッド メソッドでは、10*8的*型矩形 を出力するだけでなく、四角形の面積を計算し、メソッドの戻り値として使用します。 main メソッドでこのメソッドを呼び出し、返された領域値を受け取って出力します。
  3. 前のプログラムを変更し、メソッド メソッドに 2 つのパラメータ m と n を指定し、メソッド内で m*n的*型矩形 を出力し、メソッドの戻り値として四角形の面積を計算します。 。 main メソッドでこのメソッドを呼び出し、返された領域値を受け取って出力します。

演習 4: 属性を持つ日付タイプ MyDate: を宣言します:年year,月month,日day 2 つの日付オブジェクトを作成し、それぞれ自分の生年月日、オブジェクトの生年月日として値を割り当て、情報を表示します。

演習 5: オブジェクト指向の方法でユーザー ログイン プログラムを作成します。

ユーザークラス:

  • プロパティ: ユーザー名、パスワード
  • 方法: ログイン

インターフェースクラス:

  • ユーザー入力を受け入れ、検証のためにユーザー クラスのログイン メソッドを呼び出すための main メソッドをインターフェイス クラスに追加します。出力:
    • ログインに失敗しました: ユーザー名またはパスワードが間違っています!
    • ログイン成功: ようこそ、ユーザー名!

参照コード:

public class User {
    
    
    String name;
    String password;//密码

    /**
     * 实现用户登录的判断
     *
     * @param inputName 输入的用户名
     * @param inputPwd  输入的密码
     */
    public void login(String inputName,String inputPwd){
    
    
        if(name.equals(inputName) && password.equals(inputPwd)){
    
    
            System.out.println("登录成功:欢迎你," + name);
        }else{
    
    
            System.out.println("登录失败:用户名或密码错误!");
        }
    }

    /**
     *  实现用户登录的判断
     * @param inputName 输入的用户名
     * @param inputPwd 输入的密码
     * @return true:登录成功  false:登录失败
     */
    public boolean login1(String inputName,String inputPwd){
    
    
//        if(name.equals(inputName) && password.equals(inputPwd)){
    
    
//            return true;
//        }else{
    
    
//            return false;
//        }

        //简化为:
        return name.equals(inputName) && password.equals(inputPwd);
    }

}
/**
 *
 * 用户界面类UserInterface:
 *
 * - 在用户界面类中添加main方法,接受用户输入,并调用用户类的登录方法进行验证。
 * - 输出:
 *     - 登录失败:用户名或密码错误!
 *     - 登录成功:欢迎你,用户名!
 *
 * @author AmoXiang
 * @create 9:58
 */
public class UserInterface {
    
    
    public static void main(String[] args) {
    
    

        User u1 = new User();
        u1.name = "Tom";
        u1.password = "abc123";


        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入用户名:");
        String name = scanner.next();
        System.out.print("请输入密码:");
        String pwd = scanner.next();

        //演示1:
//        u1.login(name,pwd);

        //演示2:
        boolean isLogin = u1.login1(name, pwd);
        if(isLogin){
    
    
            System.out.println("登录成功:欢迎你," + u1.name);
        }else{
    
    
            System.out.println("登录失败:用户名或密码错误!");
        }

        scanner.close();
    }
}

6. オブジェクト配列

配列の要素は、基本データ型または参照データ型にすることができます。要素が参照型のクラスである場合、それをオブジェクトの配列と呼びます。

1.ケース

Student クラスを定義します。これには、生徒番号 (int)、成績状態 (int)、スコア (int) の 3 つの属性が含まれます。生徒番号は 1 から 20 までで、学年と学年は乱数によって決定され、20 個の生徒オブジェクトを作成します。

質問 1: 3 年生の生徒情報を出力します (状態値は 3)。
質問 2: バブル ソートを使用して学生を成績順に並べ替え、すべての学生情報を横断します。

ヒント:

  1. 乱数の生成: Math.random()、戻り値の型double;
  2. 丸め: Math.round(double d)、戻り値の型はlong。
/*
 * 定义类Student,包含三个属性:学号number(int),年级state(int),成绩score(int)。
 */
public class Student {
    
    
	
	int number;//学号
	int state;//年级
	int score;//成绩
	
	
	public void info(){
    
    
		System.out.println("number : " + number 
				+ ",state : " + state + ",score : " + score);
	}
	
}
public class StudentTest {
    
    

	public static void main(String[] args) {
    
    

		// Student s1 = new Student();
		// s1.number = 1;
		// s1.state = (int)(Math.random() * 6 + 1);//[1,6]
		// s1.score = (int)(Math.random() * 101);//[0,100]
		//
		// Student s2 = new Student();
		// s2.number = 2;
		// s2.state = (int)(Math.random() * 6 + 1);//[1,6]
		// s2.score = (int)(Math.random() * 101);//[0,100]
		//
		// //....
		// 对象数组
		// String[] arr = new String[10];
		// 数组的创建
		Student[] students = new Student[20];
		// 通过循环结构给数组的属性赋值
		for (int i = 0; i < students.length; i++) {
    
    
			// 数组元素的赋值
			students[i] = new Student();
			// 数组元素是一个对象,给对象的各个属性赋值
			students[i].number = (i + 1);
			students[i].state = (int) (Math.random() * 6 + 1);// [1,6]
			students[i].score = (int) (Math.random() * 101);// [0,100]
		}

		// 问题一:打印出3年级(state值为3)的学生信息。
		for (int i = 0; i < students.length; i++) {
    
    

			if (students[i].state == 3) {
    
    
//				System.out.println(
//	"number:" + students[i].number + ",state:" + students[i].state + ",score:" + students[i].score);
				students[i].info();
				
			}

		}
		System.out.println("******************************");
		// 问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
		// 排序前
		for (int i = 0; i < students.length; i++) {
    
    
//			System.out.println(
//					"number:" + students[i].number + ",state:" + 
//							students[i].state + ",score:" + students[i].score);
			
			students[i].info();
		}

		System.out.println();
		// 排序:
		for (int i = 0; i < students.length - 1; i++) {
    
    
			for (int j = 0; j < students.length - 1 - i; j++) {
    
    
				if (students[j].score > students[j + 1].score) {
    
    
					Student temp = students[j];
					students[j] = students[j + 1];
					students[j + 1] = temp;
				}
			}
		}

		// 排序后:
		for (int i = 0; i < students.length; i++) {
    
    
//			System.out.println(
//					"number:" + students[i].number + ",state:" + 
//							students[i].state + ",score:" + students[i].score);
			
			students[i].info();
		}

	}

}

メモリ分析:
ここに画像の説明を挿入します
2. 注。 オブジェクト配列の場合、まず配列オブジェクト自体を作成する必要があります。つまり、配列の長さを決定してから、各要素オブジェクトを作成する必要があります。作成されていない場合は、配列のデフォルト値が使用されます。要素はnullなので出現しやすい空指针异常NullPointerExceptionです。

3. 練習する

(1) 長さと幅の属性を含む長方形クラス Rectangle を定義します。area() は長方形の領域を返し、perimeter() は長方形の外周を返し、String getInfo() は円オブジェクトの詳細情報 (長さ、幅など) を返します。幅、面積、周長などのデータ)方法

(2) テスト クラスに長さ 3 の Rectangle[] 配列を作成して 3 つの長方形オブジェクトを保持し、3 つの長方形オブジェクトの長さを 10,20,30 、 < に割り当てます。 /span> トラバーサル出力5,15,25 幅は

package com.atguigu.test08.array;

public class Rectangle {
    
    
    double length;
    double width;

    public double area(){
    
    //面积
        return length * width;
    }

    public double perimeter(){
    
    //周长
        return 2 * (length + width);
    }

    public String getInfo(){
    
    
        return "长:" + length +
                ",宽:" + width +
                ",面积:" + area() +
                ",周长:" + perimeter();
    }
}
public class ObjectArrayTest {
    
    
    public static void main(String[] args) {
    
    
        //声明并创建一个长度为3的矩形对象数组
        Rectangle[] array = new Rectangle[3];

        //创建3个矩形对象,并为对象的实例变量赋值,
        //3个矩形对象的长分别是10,20,30
        //3个矩形对象的宽分别是5,15,25
        //调用矩形对象的getInfo()返回对象信息后输出
        for (int i = 0; i < array.length; i++) {
    
    
            //创建矩形对象
            array[i] = new Rectangle();

            //为矩形对象的成员变量赋值
            array[i].length = (i+1) * 10;
            array[i].width = (2*i+1) * 5;

            //获取并输出对象对象的信息
            System.out.println(array[i].getInfo());
        }
    }
}

メモリ分析:
ここに画像の説明を挿入します

7. メソッドについてもう一度話しましょう

7.1 メソッドの多重定義(オーバーロード)

7.1.1 概念と特徴

  • メソッドのオーバーロード: 同じクラス内では、パラメータ リストが異なる限り、同じ名前を持つ複数のメソッドが許可されます。
    • パラメータ リストが異なると、パラメータの数またはパラメータ タイプも異なります。
  • オーバーロードの特徴: 修飾子や戻り値の型とは関係がなく、パラメーター リストのみが異なります。パラメーター リストは異なる必要があります (パラメーターの数またはパラメーターの型)。 。呼び出されると、メソッドのパラメータ リストに従って区別されます。
  • オーバーロードされたメソッド呼び出し: JVM は、メソッドのパラメータ リストを通じて一致するメソッドを呼び出します。
    • まず、番号とタイプに最も一致するものを見つけます
    • 互換性のある別の番号と型を見つけてください。複数のメソッドが同時に互換性がある場合、エラーが報告されます。

7.1.2 例

例 1:

//System.out.println()方法就是典型的重载方法,其内部的声明形式如下:
public class PrintStream {
    
    
    public void println(byte x)
	public void println(short x)
	public void println(int x)
	public void println(long x)
	public void println(float x)
	public void println(double x)
	public void println(char x)
	public void println(double x)
	public void println()
}
public class HelloWorld{
    
    
    public static void main(String[] args) {
    
    
        System.out.println(3);
        System.out.println(1.2f);
        System.out.println("hello!");
    }
}

例 2:

//返回两个整数的和
public int add(int x,int y){
    
    
    return x+y;
}

//返回三个整数的和
public int add(int x,int y,int z){
    
    
    return x+y+z;
}
//返回两个小数的和
public double add(double x,double y){
    
    
    return x+y;
}

例 3: メソッドのオーバーロードは戻り値の型とは関係ありません

public class MathTools {
    
    
    //以下方法不是重载,会报错
    public int getOneToHundred(){
    
    
    	return (int)(Math.random()*100);
    }
    
    public double getOneToHundred(){
    
    
    	return Math.random()*100;
    }
}

7.1.3 演習

演習 1: 判断と void show(int a,char b,double c){} はオーバーロードを構成します:

a)void show(int x,char y,double z){
    
    }     // no
b)int show(int a,double c,char b){
    
    }      // yes
c) void show(int a,double c,char b){
    
    }    // yes
d) boolean show(int c,char b){
    
    }          // yes
e) void show(double c){
    
    }                 // yes
f) double show(int x,char y,double z){
    
    }  // no
g) void shows(){
    
    double c}                // no

演習 2: プログラムを作成し、3 つのオーバーロードされたメソッドを定義して呼び出します。

  • この方法はmOLと呼ばれます。
  • 3 つのメソッドは、それぞれ 1 つの int パラメーター、2 つの int パラメーター、および 1 つの string パラメーターを受け取ります。それぞれ二乗演算を実行して結果を出力、乗算して結果を出力、文字列情報を出力します。
  • メインクラスの main() メソッドでは、3 つのメソッドがパラメータを指定して個別に呼び出されます。

演習 3: 3 つのオーバーロード メソッド max() を定義します。最初のメソッドは 2 つの int 値の最大値を見つけ、2 番目のメソッドは 2 つの double 値を見つけます。3 番目のメソッドは次の値を見つけます。 3 つの double 値のうちの最大値を取得し、それぞれ 3 つのメソッドを呼び出します。

7.2 可変数の仮パラメータ

JDK5.0 で提供Varargs( 変数番号引数) メカニズム。つまり、メソッドを定義するときに、仮パラメータのタイプは決定できますが、仮パラメータの数が不確実な場合は、可変数の仮パラメータの使用を検討できます。 形式:

方法名(参数的类型名 ...参数名)

例:

//JDK 5.0以前:采用数组形参来定义方法,传入多个同一类型变量
public static void test(int a ,String[] books);

//JDK5.0:采用可变个数形参来定义方法,传入多个同一类型变量
public static void test(int a ,String...books);

特徴:

  1. 可変パラメータ:メソッドパラメータ部の指定型のパラメータ数が可変:0、1以上
  2. 可変数の仮パラメータを持つメソッドと同じ名前を持つメソッドは、相互にオーバーロードを形成します。
  3. 可変パラメータ メソッドの使用は、メソッド パラメータ部分での配列の使用と一致しています。同時に宣言することはできません。宣言しない場合は、エラーが報告されます。
  4. メソッドのパラメーター部分には可変パラメーターがあり、仮パラメーター宣言の最後に配置する必要があります。
  5. メソッドの仮パラメータでは、最大 1 つの変数の仮パラメータを宣言できます。

事例分析:

ケース 1: n 個の文字列を連結し、特定の文字を使用して各文字列を区切ります。文字列が渡されない場合は、空の文字列 """ が返されます。

public class StringTools {
    
    
    String concat(char seperator, String... args){
    
    
        String str = "";
        for (int i = 0; i < args.length; i++) {
    
    
            if(i==0){
    
    
                str += args[i];
            }else{
    
    
                str += seperator + args[i];
            }
        }
        return str;
    }
}
public class StringToolsTest {
    
    
    public static void main(String[] args) {
    
    
        StringTools tools = new StringTools();

        System.out.println(tools.concat('-'));
        System.out.println(tools.concat('-',"hello"));
        System.out.println(tools.concat('-',"hello","world"));
        System.out.println(tools.concat('-',"hello","world","java"));
    }
}

ケース 2: n 個の整数の合計を求める

public class NumberTools {
    
    
    public int total(int[] nums){
    
    
        int sum = 0;
        for (int i = 0; i < nums.length; i++) {
    
    
            sum += nums[i];
        }
        return sum;
    }

    public int sum(int... nums){
    
    
        int sum = 0;
        for (int i = 0; i < nums.length; i++) {
    
    
            sum += nums[i];
        }
        return sum;
    }
}
public class TestVarParam {
    
    
    public static void main(String[] args) {
    
    
        NumberTools tools = new NumberTools();

        System.out.println(tools.sum());//0个实参
        System.out.println(tools.sum(5));//1个实参
        System.out.println(tools.sum(5,6,2,4));//4个实参
        System.out.println(tools.sum(new int[]{
    
    5,6,2,4}));//传入数组实参

        System.out.println("------------------------------------");
        System.out.println(tools.total(new int[]{
    
    }));//0个元素的数组
        System.out.println(tools.total(new int[]{
    
    5}));//1个元素的数组
        System.out.println(tools.total(new int[]{
    
    5,6,2,4}));//传入数组实参
    }
}

ケース 3: 次のメソッドは相互にオーバーロードを構成します

public class MathTools {
    
    
    //求两个整数的最大值
    public int max(int a,int b){
    
    
        return a>b?a:b;
    }

    //求两个小数的最大值
    public double max(double a, double b){
    
    
        return a>b?a:b;
    }

    //求三个整数的最大值
    public int max(int a, int b, int c){
    
    
        return max(max(a,b),c);
    }
    
    //求n个整数的最大值
    public int max(int... nums){
    
    
        int max = nums[0];//如果没有传入整数,或者传入null,这句代码会报异常
        for (int i = 1; i < nums.length; i++) {
    
    
            if(nums[i] > max){
    
    
                max = nums[i];
            }
        }
        return max;
    }
    /*    //求n整数的最大值
    public int max(int[] nums){  //编译就报错,与(int... nums)无法区分
        int max = nums[0];//如果没有传入整数,或者传入null,这句代码会报异常
        for (int i = 1; i < nums.length; i++) {
            if(nums[i] > max){
                max = nums[i];
            }
        }
        return max;
    }*/

/*    //求n整数的最大值
    public int max(int first, int... nums){  //当前类不报错,但是调用时会引起多个方法同时匹配
        int max = first;
        for (int i = 0; i < nums.length; i++) {
            if(nums[i] > max){
                max = nums[i];
            }
        }
        return max;
    }*/
}

7.3 メソッドパラメータの受け渡しメカニズム

7.3.1 仮パラメータと実パラメータ

仮パラメータ: メソッドを定義する場合、メソッド名の後にかっこ () 内で宣言された変数は、仮パラメータ、または略して仮パラメータと呼ばれます。
実パラメータ: メソッドを呼び出すときに、メソッド名の後の括弧 () 内で使用される値/変数/式は、実パラメータ、または略して実パラメータと呼ばれます。

7.3.2 パラメータ受け渡しメカニズム: 値の受け渡し

Java でパラメータをメソッドに渡す方法は 1 つだけです:值传递。つまり、実際のパラメータ値のコピー (レプリカ) がメソッドに渡されますが、パラメータ自体は影響を受けません。

  • 仮パラメータは基本データ型です。実パラメータの基本データ型変数のデータ値を仮パラメータに渡します。あ>
  • 仮パラメータは参照データ型です。実パラメータの参照データ型変数のアドレス値を仮パラメータに渡します。あ>

7.3.3 例

1. 仮パラメータは基本的なデータ型です

ケース: 2 つの整数変数の値を交換するメソッドを作成する

public class Test {
    
    
	public static void main(String[] args) {
    
    
		int m = 10;
		int n = 20;
		
		System.out.println("m = " + m + ", n = " + n);
		//交换m和n的值
//		int temp = m;
//		m = n;
//		n = temp;
		
		ValueTransferTest1 test = new ValueTransferTest1();
		test.swap(m, n);
		
		System.out.println("m = " + m + ", n = " + n);
	}
	
	public void swap(int m,int n){
    
    
		int temp = m;
		m = n;
		n = temp;
	}
	
}

メモリ分析:
ここに画像の説明を挿入します
2. 仮パラメータは参照データ型です

public class Test {
    
    
	public static void main(String[] args) {
    
    
		
		Data d1 = new Data();
		d1.m = 10;
		d1.n = 20;
		
		System.out.println("m = " + d1.m + ", n = " + d1.n);
		
		//实现 换序
		
		ValueTransferTest2 test = new ValueTransferTest2();
		test.swap(d1);
		
		System.out.println("m = " + d1.m + ", n = " + d1.n);
		
	}
	
	public void swap(Data data){
    
    
		int temp = data.m;
		data.m = data.n;
		data.n = temp;
	}
}
class Data{
    
    
	int m;
	int n;
}

メモリ分析:
ここに画像の説明を挿入します

7.3.4 演習

演習 1: 次のプログラムの出力を求めます。

public class AssignNewObject {
    
    
    public void swap(MyData my){
    
    
        my = new MyData(); //考虑堆空间此新创建的对象,和main中的data对象是否有关
        int temp = my.x;
        my.x = my.y;
        my.y = temp;
     
    }

    public static void main(String[] args) {
    
    
        AssignNewObject tools = new AssignNewObject();
        
        MyData data = new MyData();
        data.x = 1;
        data.y = 2;
        System.out.println("交换之前:x = " + data.x +",y = " + data.y);//
        tools.swap(data);//调用完之后,x与y的值交换?
        System.out.println("交换之后:x = " + data.x +",y = " + data.y);//
    }
}

class MyData{
    
    
    int x ;
    int y;
}

演習 2: 次の操作を使用して配列の並べ替えを実行できますか?

public class ArrayTypeParam {
    
    

    //冒泡排序,实现数组从小到大排序
    public void sort(int[] arr){
    
    
        for (int i = 0; i < arr.length - 1; i++) {
    
    
            for (int j = 0; j < arr.length - 1 - i; j++) {
    
    
                if(arr[j] > arr[j+1]){
    
    
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
    }
    //打印数组的元素
    public void print(int[] arr){
    
    
        for (int i = 0; i < arr.length; i++) {
    
    
            System.out.print(arr[i]+" ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
    
    
        ArrayTypeParam tools = new ArrayTypeParam();

        int[] nums = {
    
    4,3,1,6,7};
        System.out.println("排序之前:");
        tools.print(nums);

        tools.sort(nums);//对nums数组进行排序

        System.out.println("排序之后:");
        tools.print(nums);//输出nums数组的元素

    }
}

演習 3: 次のプログラムの出力結果をメモリ構造図に従って記述してください

//栈:每个方法在调用时,都会有以栈帧的方法压入栈中。栈帧中保存了当前方法中声明的变量:方法内声明的,形参
//堆:存放new出来的"东西":对象(成员变量在对象中)、数组实体(数组元素)。 
//注意:变量前如果声明有类型,那么这就是一个新的刚要定义的变量。如果变量前没有声明类型,那就说明此变量在之前已经声明过。
public class TransferTest3 {
    
    
    public static void main(String args[]) {
    
    
        TransferTest3 test = new TransferTest3();
        test.first();
    }
    public void first() {
    
    
        int i = 5;
        Value v = new Value();
        v.i = 25;
        second(v, i);
        System.out.println(v.i);
    }
    public void second(Value v, int i) {
    
    
        i = 0;
        v.i = 20;
        Value val = new Value();
        v = val;
        System.out.println(v.i + " " + i);
    }
}

class Value {
    
    
    int i = 15;
}

メモリ分析:
ここに画像の説明を挿入します
演習 4:貌似是 メソッドのパラメータ渡しを調べる
ここに画像の説明を挿入します

	//法一:
    public static void method(int a, int b) {
    
    
        // 在不改变原本题目的前提下,如何写这个函数才能在main函数中输出a=100,b=200? 
        a = a * 10;
        b = b * 20;
        System.out.println(a);
        System.out.println(b);
        System.exit(0);
    }

    //法二:
    public static void method(int a, int b) {
    
    

        PrintStream ps = new PrintStream(System.out) {
    
    
            @Override
            public void println(String x) {
    
    

                if ("a=10".equals(x)) {
    
    
                    x = "a=100";
                } else if ("b=10".equals(x)) {
    
    
                    x = "b=200";
                }
                super.println(x);
            }
        };

        System.setOut(ps);

    }

演習 5: オブジェクトをパラメータとしてメソッドに渡す

  1. 円の半径を表す double radius プロパティと、円の面積を返す findArea() メソッドを含む Circle クラスを定義します。
  2. クラス PassObject を定義し、クラス内にメソッド printAreas() を定義します。メソッドは次のように定義されます: public void printAreas(Circle c,int time) printAreas で印刷します。メソッド 1 から時間までの各整数の半径値と、対応する領域を出力します。たとえば、times が 5 の場合、出力半径は 1,2,3,4,5 および対応する円の領域になります。
  3. main メソッドで printAreas() メソッドを呼び出し、呼び出しの完了後に現在の半径値を出力します。プログラムの実行結果は以下のようになります。
    ここに画像の説明を挿入します

7.4 再帰法

举例1:
ここに画像の説明を挿入します
举例2:

从前有座山,山上有座庙,庙里有个老和尚,老和尚在给小和尚讲故事,讲的啥?
      从前有座山,山上有座庙,庙里有个老和尚,老和尚在给小和尚讲故事,讲的啥?
          从前有座山,山上有座庙,庙里有个老和尚,老和尚在给小和尚讲故事,讲的啥?
              从前有座山,山上有座庙,庙里有个老和尚,老和尚在给小和尚讲故事,讲的啥?...
    			...
老和尚没了,庙塌了,小和尚还俗结婚了。

再帰的メソッド呼び出し: メソッド自体が呼び出される現象は再帰と呼ばれます。
再帰の分類: 直接再帰、間接再帰。

直接再帰: メソッドはそれ自体を呼び出します。

public void methodA(){
    
    
	methodA();
}

間接再帰: メソッド A() がメソッド B() を呼び出し、メソッド B() がメソッド C() を呼び出し、メソッド C() がメソッド A() を呼び出すことがわかります。

public static void A(){
    
    
	B();
}

public static void B(){
    
    
	C();
}

public static void C(){
    
    
	A();
}

说明

  1. 再帰メソッドには 隐式的循环 が含まれています。
  2. 再帰的メソッドは重复执行コードの特定のセクションを実行しますが、この繰り返しの実行にはループ制御は必要ありません。
  3. 再帰は 已知方向 まで再帰する必要があります。そうでない場合、この再帰は 死循环 と同様に無限再帰となり、停止できません。最終的には栈内存溢出起こります。

例 1: 1 ~ n の合計を計算する

public class RecursionDemo {
    
    
	public static void main(String[] args) {
    
    
        RecursionDemo demo = new RecursionDemo();
		//计算1~num的和,使用递归完成
		int num = 5;
      	// 调用求和的方法
		int sum = demo.getSum(num);
      	// 输出结果
		System.out.println(sum);
		
	}
  	/*
  	  通过递归算法实现.
  	  参数列表:int 
  	  返回值类型: int 
  	*/
	public int getSum(int num) {
    
    
      	/* 
      	   num为1时,方法返回1,
      	   相当于是方法的出口,num总有是1的情况
      	*/
		if(num == 1){
    
    
			return 1;
		}
      	/*
          num不为1时,方法返回 num +(num-1)的累和
          递归调用getSum方法
        */
		return num + getSum(num-1);
	}
}

コード実行図:
ここに画像の説明を挿入します
例 2: n を計算する再帰的メソッド!

public int multiply(int num){
    
    
	if(num == 1){
    
    
		return 1;
	}else{
    
    
		return num * multiply(num - 1);
	}
}

ここに画像の説明を挿入します
例 3: f(0)=1、f(1)=4、f(n+2)=2*f(n+1)+f(n) というシーケンスがあることがわかっています。ここで、n は0 より大きい整数の場合は、f(10) の値を見つけます。

public int f(int num){
    
    
	if(num == 0){
    
    
		return 1;
	}else if(num == 1){
    
    
		return 4;
	}else{
    
    
		return 2 * f(num - 1) + f(num - 2);
	}
}

例 4: 与えられたシーケンス: f(20) = 1,f(21) = 4,f(n+2) = 2*f(n+1)+f(n)、n は 0 より大きい整数、f(10)の値を求めます。

public int func(int num){
    
    
	if(num == 20){
    
    
		return 1;
	}else if(num == 21){
    
    
		return 4;
	}else{
    
    
		return func(num + 2) - 2 * func(num + 1);
	}
}

例 5: フィボナッチ数列の n 番目の値 (フィボナッチ) を計算します。フィボナッチ数列は次の規則を満たします。

1,1,2,3,5,8,13,21,34,55,....

つまり、3 番目の数値から始まる数値は、最初の 2 つの数値の合計と等しくなります。 f(n) がフィボナッチ数列の n 番目の値を表すと仮定すると、f(n) は次の条件を満たします。
f(n) = f(n-2) + f(n-1);

	//使用递归的写法
    int f(int n) {
    
    //计算斐波那契数列第n个值是多少
        if (n < 1) {
    
    //负数是返回特殊值1,表示不计算负数情况
            return 1;
        }
        if (n == 1 || n == 2) {
    
    
            return 1;
        }
        return f(n - 2) + f(n - 1);
    }

    //不用递归
    int fValue(int n) {
    
    //计算斐波那契数列第n个值是多少
        if (n < 1) {
    
    //负数是返回特殊值1,表示不计算负数情况
            return 1;
        }
        if (n == 1 || n == 2) {
    
    
            return 1;
        }
        //从第三个数开始,  等于 前两个整数相加
        int beforeBefore = 1; //相当于n=1时的值
        int before = 1;//相当于n=2时的值
        int current = beforeBefore + before; //相当于n=3的值
        //再完后
        for (int i = 4; i <= n; i++) {
    
    
            beforeBefore = before;
            before = current;
            current = beforeBefore + before;
            /*
            假设i=4
                beforeBefore = before; //相当于n=2时的值
                before = current; //相当于n=3的值
                current = beforeBefore + before; //相当于n = 4的值
            假设i=5
                beforeBefore = before; //相当于n=3的值
                before = current; //相当于n = 4的值
                current = beforeBefore + before; //相当于n = 5的值
                ....
             */
        }
        return current;
    }

例 6: 面接の質問
ここに画像の説明を挿入します

	private int count = 0;

    public int recursion(int k) {
    
    
        count++;
        System.out.println("count1:" + count + "  k:" + k);
        if (k <= 0) {
    
    
            return 0;
        }
        return recursion(k - 1) + recursion(k - 2);//287
        //return recursion(k - 1);//11
        //return recursion(k - 1) + recursion(k - 1);//2047
    }

分析:
ここに画像の説明を挿入します
最後に 2 つの言葉:

  1. 再帰呼び出しは、大量のシステム スタックを占有し、大量のメモリを消費します。再帰呼び出しのレベルが多い場合、ループよりも高速です慢的多。そのため、再帰呼び出しを行う場合は注意してください。再帰を使用します。
  2. 高いパフォーマンスが必要な場合は、再帰の使用を避けてください。再帰呼び出しには時間がかかり、耗内存ループ反復の使用を検討してください

8. キーワード: パッケージ、インポート

8.1パッケージ

パッケージ (パッケージと呼ばれます) は、ファイル内で定義されたクラス、インターフェイス、およびその他の構造が配置されているパッケージを示すために使用されます。

8.1.1 構文形式

package 顶层包名.子包名 ;

例: Pack1\pack2\PackageTest.java

package pack1.pack2;    //指定类PackageTest属于包pack1.pack2

public class PackageTest{
    
    
	public void display(){
    
    
		System.out.println("in  method display()");
	}
}

例証します:

  • ソース ファイルには、パッケージを宣言する package ステートメントを 1 つだけ含めることができます。
  • package ステートメントは、Java ソース ファイルの最初のステートメントとして表示されます。このステートメントがデフォルトで省略された場合、名前のないパッケージが指定されます。
  • パッケージ名は識別子であり、識別子の命名規則と仕様 (すべて小文字) を満たしており、その意味は名前によってわかります。
    • 通常、パッケージでは会社のドメイン名を逆にしたもの (com.csdn.xxx) が使用されます。
    • パッケージに名前を付けるときは、java.xx package を使用しないでください。
  • パッケージはファイル システムのディレクトリに対応します。. はパッケージ ステートメントでパッケージ (ディレクトリ) のレベルを示すために使用されます。各 .一次 はファイルのレイヤーを表します。
  • 同一パッケージ内で複数の構造体(クラス、インターフェース)を宣言できますが、同じ名前の構造体(クラス、インターフェース)を定義することはできません。同じ名前の構造体 (クラス、インターフェイス) を異なるパッケージで定義できます。

8.1.2 パッケージの役割

  • パッケージにはクラスとサブパッケージを含めることができ、项目层次管理が容易になるように分割できます
  • ヘルプ管理大型软件システム: 同様の機能を持つクラスは同じパッケージに分割されています。例: MVC 設計パターン
  • 解决类命名冲突的问题
  • コントロール访问权限

8.1.3 応用例

例 1: 出荷用ソフトウェア システムには次のものが含まれます: 一連のドメイン オブジェクト、GUI、レポート サブシステム
ここに画像の説明を挿入します
例 2: MVC 設計パターン

MVC は、プログラム開発におけるコード操作の結合を減らすことを目的としたソフトウェア コンポーネント モデルです。 MVC デザイン パターンは、プログラム全体を 视图模型(Viewer)层控制器(Controller)层数据模型(Model)层 の 3 つのレベルに分割します。プログラムの入出力、データ処理、データ表示を分離する設計パターンにより、プログラム構造を柔軟かつ明確にし、プログラムの各オブジェクト間の通信方法を記述し、プログラムの結合を軽減します。

视图层viewer:显示数据,为用户提供使用界面,与用户直接进行交互。
 >相关工具类   view.utils
 >自定义view  view.ui

控制层controller:解析用户请求,处理业务逻辑,给予用户响应
 >应用界面相关    controller.activity
 >存放fragment   controller.fragment
 >显示列表的适配器 controller.adapter
 >服务相关的        controller.service
 >抽取的基类        controller.base
    
模型层model:主要承载数据、处理数据
 >数据对象封装 model.bean/domain
 >数据库操作类 model.dao
 >数据库      model.db

ここに画像の説明を挿入します

8.1.4 JDK の主要パッケージの紹介

java.lang ---- String、Math、Integer、System、Thread などの Java 言語のコア クラスが含まれており、共通の関数を提供します。
java.net ---- 関連する関数が含まれています。ネットワークの動作クラスとインターフェイス。
java.io ---- さまざまな入出力関数を提供するクラスが含まれています。
java.util ---- システム機能やインターフェイスを定義したり、日付やカレンダーに関連する関数を使用したりするためのコレクション フレームワーク クラスなど、いくつかのユーティリティ クラスが含まれています。
java.text ---- Java フォーマット関連のクラスが含まれています
java.sql ---- JDBC データベース プログラミング用の Java 関連のクラス/インターフェイスが含まれています
java.awt ---- アプリケーションのグラフィカル ユーザー インターフェイス (GUI) を構築および管理するために使用される、抽象ウィンドウ ツールキット (抽象ウィンドウ ツールキット) を構成する複数のクラスが含まれています。

8.2 インポート(インポート)

他のパッケージで定義された Java クラスを使用するには、import ステートメントを使用して、指定したパッケージに必要なクラスを明示的に導入する必要があります。 import语句告诉编译器到哪里去寻找这个类 に相当します。

8.2.1 構文形式

import 包名.类名;

8.2.2 応用例

import pack1.pack2.Test;   //import pack1.pack2.*;表示引入pack1.pack2包中的所有结构

public class PackTest{
    
    
	public static void main(String args[]){
    
    
		Test t = new Test();          //Test类在pack1.pack2包中定义
		t.display();
	}
}

8.2.3 注意事項

  • import ステートメント。パッケージ宣言とクラス宣言の間で宣言されます。
  • 複数のクラスまたはインターフェイスをインポートする必要がある場合は、複数の import ステートメントを並行して発行します。
  • a.* を使用して構造をインポートする場合、パッケージ a の下にあるすべての構造をインポートできることを意味します。例: java.util.* を使用すると、util パッケージ内のすべてのクラスまたはインターフェイスを一度にインポートできます。
  • インポートされたクラスまたはインターフェイスが java.lang パッケージまたは現在のパッケージの下にある場合は、この import ステートメントを省略できます。
  • java.a パッケージの下にクラスをインポートした場合でも、a パッケージのサブパッケージの下にあるクラスを使用する必要がある場合は、それらをインポートする必要があります。
  • コード内の異なるパッケージで同じ名前のクラスを使用する場合は、そのクラスの完全なクラス名を使用して、どのクラスが呼び出されているかを示す必要があります。
  • (理解) import static 組み合わせの使用: 指定されたクラスまたはインターフェイスで静的プロパティまたはメソッドを呼び出す

9. オブジェクト指向の機能 1: カプセル化

9.1 カプセル化はなぜ必要ですか?

洗濯機を使いたいのですが、スイッチを入れて洗濯モードにするだけです。洗濯機の内部構造を理解する必要はありますか?モーターに触れる必要はありますか?運転したいのですが、クラッチ、アクセル、ブレーキなどの原理やメンテナンスを理解していなくても運転できます。客観世界のあらゆる物の内部情報は内部に隠されており、外部から直接操作・変更することはできず、指定された方法でのみアクセス・変更することができます。システムがますます複雑になり、クラスの数が増えるにつれて、クラス間のアクセス境界をよく把握し、オブジェクト指向の開発原則に従う必要があります 高内聚、低耦合

高い凝集性と低い結合性はソフトウェア エンジニアリングの概念であり、UNIX オペレーティング システム設計の古典的な原則でもあります。
凝集度は、モジュール内の要素が互いにどの程度密接に結合しているかを指します。結合度は、ソフトウェア構造内の異なるモジュール間の相互接続の度合いの測定値を指します。結合とは再利用と独立性を意味し、結合とはドミノ効果が全体に影響を及ぼすことを意味します。

そして 高内聚,低耦合 の症状の 1 つ:

  • 高内聚: クラスの内部データ操作の詳細は自分自身で完了し、外部からの干渉は許可されません。
  • 低耦合: 外部使用のために少数のメソッドのみを公開し、外部呼び出しを容易にするように努めてください。

9.2 カプセル化とは何ですか?

いわゆるカプセル化とは、客観的なものを抽象概念のクラスにカプセル化することであり、クラスは自身のデータやメソッドを信頼できるクラスやオブジェクトに対してのみ開くことができ、開く必要のないクラスやオブジェクトからは情報を隠すことができます。

平たく言えば、隠すべきものは隠し、暴露すべきものは暴露する。これがカプセル化の設計思想です。

9.3 Java がデータのカプセル化を実装する方法

カプセル化を実装するとは、クラスまたはメンバーの可視範囲を制御することになります。これには、アクセス制御修飾子 (アクセス許可修飾子とも呼ばれます) に依存する必要があります。権限修飾子: publicprotected缺省private。具体的なアクセス範囲は次のとおりです。

修飾子 このクラス内では 本包内 他のパッケージのサブクラス 他のパッケージはサブクラスではありません
プライベート × × ×
デフォルト × ×
保護された ×
公共

具体的に変更された構造:

  • 外部クラス: public、default
  • メンバー変数、メンバー メソッド、コンストラクター、メンバー内部クラス: public、protected、default、private

ここに画像の説明を挿入します
ここに画像の説明を挿入します

9.4 カプセル化の反映

9.4.1 メンバー変数/プロパティのプライベート化

概要: クラスのメンバー変数をプライベート化し、パブリックな get メソッドと set メソッドを提供し、プロパティの取得と変更の機能を外部に公開します。

实现步骤: 使用 private 修饰成员变量

private 数据类型 变量名 ;

コードは以下のように表示されます:

public class Person {
    
    
    private String name;
  	private int age;
    private boolean marry;
}

はメンバー変数にアクセスできる getXxx メソッド / setXxx メソッドを提供します。コードは次のとおりです。

public class Person {
    
    
    private String name;
  	private int age;
    private boolean marry;

	public void setName(String n) {
    
    
		name = n;
    }

    public String getName() {
    
    
        return name;
	}

    public void setAge(int a) {
    
    
        age = a;
    }

    public int getAge() {
    
    
        return age;
    }
    
    public void setMarry(boolean m){
    
    
        marry = m;
    }
    
    public boolean isMarry(){
    
    
        return marry;
    }
}

测试:

public class PersonTest {
    
    
    public static void main(String[] args) {
    
    
        Person p = new Person();

        //实例变量私有化,跨类是无法直接使用的
		/* p.name = "张三";
        p.age = 23;
        p.marry = true;*/

        p.setName("张三");
        System.out.println("p.name = " + p.getName());

        p.setAge(23);
        System.out.println("p.age = " + p.getAge());

        p.setMarry(true);
        System.out.println("p.marry = " + p.isMarry());
    }
}

メンバー変数のカプセル化の利点:

  • ユーザーが所定のメソッドを介してのみアクセスできるようにする访问数据。これにより、メソッドに制御ロジックを追加して、メンバー変数への不当なアクセスを制限できます。データ検査を実行して、オブジェクト情報の整合性を確保することもできます。
  • 便于修改、コードの保守性が向上します。重要なのは、隠れた部分が内部的に変更されているということであり、外部へのアクセス方法が変更されない限り、外部からはその変更がまったく感じられません。例: Java8->Java9、文字列は内部実装のために char[] から byte[] に変換されますが、外部メソッドは変更されず、ユーザーは内部の変更をまったく感じられません。

幸せそうに微笑みます:

A man and woman are in a computer programming lecture. The man touches the woman's breasts.
"Hey!" she says. "Those are private!"
The man says, "But we're in the same class!"

9.4.2 民営化の手法

/**
 * 
 * @Description 自定义的操作数组的工具类
 * @author AmoXiang [email protected]
 * @version
 *
 */
public class ArrayUtil {
    
    

	/**
	 * 
	 * @Description 求int型数组的最大值
	 * @author AmoXiang
	 * @param arr
	 * @return
	 */
	public int max(int[] arr) {
    
    
		int maxValue = arr[0];
		for(int i = 1;i < arr.length;i++){
    
    
			if(maxValue < arr[i]){
    
    
				maxValue = arr[i];
			}
		}
		return maxValue;
	}

	/**
	 * 
	 * @Description 求int型数组的最小值
	 * @author AmoXiang
	 * @param arr
	 * @return
	 */
	public int min(int[] arr){
    
    
		int minValue = arr[0];
		for(int i = 1;i < arr.length;i++){
    
    
			if(minValue > arr[i]){
    
    
				minValue = arr[i];
			}
		}
		return minValue;
	}

	/**
	 * 
	 * @Description 求int型数组的总和
	 * @author AmoXiang
	 * @param arr
	 * @return
	 */
	public int sum(int[] arr) {
    
    
		int sum = 0;
		for(int i = 0;i < arr.length;i++){
    
    
			sum += arr[i];
		}
		return sum;
	}

	/**
	 * 
	 * @Description 求int型数组的元素的平均值
	 * @author AmoXiang
	 * @param arr
	 * @return
	 */
	public int avg(int[] arr) {
    
    
		int sumValue = sum(arr);
		return sumValue / arr.length;
	}

	// 创建一系列重载的上述方法
	// public double max(double[] arr){}
	// public float max(float[] arr){}
	// public byte max(byte[] arr){}

	/**
	 * 
	 * @Description 遍历数组
	 * @author AmoXiang
	 * @param arr
	 */
	public void print(int[] arr) {
    
    
		for(int i = 0;i < arr.length;i++){
    
    
			System.out.print(arr[i] + "  ");
		}
		System.out.println();
	}

	/**
	 * 
	 * @Description 复制数组arr
	 * @author AmoXiang
	 * @param arr
	 * @return
	 */
	public int[] copy(int[] arr) {
    
    
		int[] arr1 = new int[arr.length];
		for(int i = 0;i < arr.length;i++){
    
    
			arr1[i] = arr[i];
		}
		return arr1;
	}

	/**
	 * 
	 * @Description 反转数组
	 * @author AmoXiang
	 * @param arr
	 */
	public void reverse(int[] arr) {
    
    
		for(int i = 0,j = arr.length - 1;i < j;i++,j--){
    
    
			int temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;
		}
	}

	/**
	 * 
	 * @Description 数组的排序
	 * @author AmoXiang
	 * @param arr
	 * @param desc 指明排序的方式。 ascend:升序    descend:降序
	 */
	public void sort(int[] arr,String desc) {
    
    
		
		if("ascend".equals(desc)){
    
    //if(desc.equals("ascend")){
    
    
			for (int i = 0; i < arr.length - 1; i++) {
    
    
				for (int j = 0; j < arr.length - 1 - i; j++) {
    
    
					if (arr[j] > arr[j + 1]) {
    
    
//						int temp = arr[j];
//						arr[j] = arr[j + 1];
//						arr[j + 1] = temp;
						swap(arr,j,j+1);
					}
				}
			}
		}else if ("descend".equals(desc)){
    
    
			for (int i = 0; i < arr.length - 1; i++) {
    
    
				for (int j = 0; j < arr.length - 1 - i; j++) {
    
    
					if (arr[j] < arr[j + 1]) {
    
    
//						int temp = arr[j];
//						arr[j] = arr[j + 1];
//						arr[j + 1] = temp;
						swap(arr,j,j+1);
					}
				}
			}
		}else{
    
    
			System.out.println("您输入的排序方式有误!");
		}
	}
	
	private void swap(int[] arr,int i,int j){
    
    
		int temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}

	/**
	 * 
	 * @Description 查找指定的value值在arr数组中出现的位置
	 * @author AmoXiang
	 * @param arr
	 * @param value
	 * @return 返回value值出现的位置 或 -1:未找到
	 */
	public int getValue(int[] arr, int value) {
    
    
		//方法:线性查找
		for(int i = 0;i < arr.length;i++){
    
    
			if(value == arr[i]){
    
    
				return i;
			}
		}
		
		return - 1;
	}
}

知らせ:

  1. 開発では、メンバー インスタンス変数にプライベートな変更を使用し、対応する get/set メソッドへのアクセスをパブリックなアクセス許可で提供するのが一般的です。
  2. 最終インスタンス変数の場合、set() メソッドは提供されません。 (最後のキーワードについては後ほどお話します)
  3. 静的な最終メンバー変数の場合は、パブリック変更を使用するのが一般的です。

9.5 演習

演習 1: プログラムを作成します。プログラム内に 2 つのクラス、つまり Person クラスと PersonTest クラスを定義します。定義は次のとおりです。

setAge() を使用してその人の法定年齢 (0 ~ 130) を設定し、getAge() を使用してその人の年齢を返します。 PERSONTest クラスで PERSON クラスのオブジェクト b をインスタンス化し、setAge() メソッドと getAge() メソッドを呼び出して、Java のカプセル化を体験します。
ここに画像の説明を挿入します
演習 2: 書籍クラスをカスタマイズします。設定される属性には書籍名、著者、出版社、価格が含まれ、メソッドには対応する属性の取得/設定メソッド、書籍情報の紹介などが含まれます。

10. クラスの 3 番目のメンバー: コンストラクター (Constructor)

オブジェクトを新規作成すると、すべてのメンバー変数にデフォルト値が設定されますが、他の値を代入する必要がある場合は、1 つずつ代入する必要があり、非常に面倒です。オブジェクトを新規作成するときに、現在のオブジェクトの一部またはすべてのメンバー変数に値を直接代入できますか?はい、Java は 构造器(Constructor) (构造方法 とも呼ばれます) を提供します。

10.1 コンストラクターの役割

新しいオブジェクトを作成し、新しいオブジェクトが使用されるときにインスタンス変数に値を代入します。

举例:Person p = new Person("Peter",15);

説明: すべての は生まれたらすぐにお風呂に入らなければならないと規定しているのと同じように、 のコンストラクターに補完を追加できます。 そうするように伝えてください。 、プログラムは長いものは、各人が生まれたときに 1 つずつ完了する必要があります。 が生成されるとすぐに自動的に完成します。洗澡 のプログラム コード。各 洗澡洗澡

10.2 コンストラクタの構文形式

[修饰符] class 类名{
    
    
    [修饰符] 构造器名(){
    
    
    	// 实例初始化代码
    }
    [修饰符] 构造器名(参数列表){
    
    
        // 实例初始化代码
    }
}

例証します:

  1. コンストラクターの名前は、それが配置されているクラスの名前と同じである必要があります。
  2. 戻り値がないため、戻り値の型も void も必要ありません。
  3. コンストラクターの修飾子は権限修飾子のみにすることができ、他のものによって変更することはできません。たとえば、static、final、synchronized、abstract、または Native によって変更することはできません。また、値を返す return ステートメントを含めることはできません。

コードは以下のように表示されます:

public class Student {
    
    
    private String name;
    private int age;

    // 无参构造
    public Student() {
    
    }

    // 有参构造
    public Student(String n,int a) {
    
    
        name = n;
        age = a;
    }

    public String getName() {
    
    
        return name;
    }
    public void setName(String n) {
    
    
        name = n;
    }
    public int getAge() {
    
    
        return age;
    }
    public void setAge(int a) {
    
    
        age = a;
    }

    public String getInfo(){
    
    
        return "姓名:" + name +",年龄:" + age;
    }
}
public class TestStudent {
    
    
    public static void main(String[] args) {
    
    
        //调用无参构造创建学生对象
        Student s1 = new Student();

        //调用有参构造创建学生对象
        Student s2 = new Student("张三",23);

        System.out.println(s1.getInfo());
        System.out.println(s2.getInfo());
    }
}

10.3 使用説明書

クラス内でコンストラクターを明示的に宣言しない場合、システムはデフォルトでパラメーターなしのコンストラクターを提供し、コンストラクターの修飾子はデフォルトでクラスの修飾子と同じになります。
ここに画像の説明を挿入します
クラスのコンストラクターを明示的に定義すると、システムはデフォルトのパラメーターなしのコンストラクターを提供しなくなります。クラスには少なくとも 1 つのコンストラクターが存在します。コンストラクターはオーバーロードできます。

10.4 演習

演習 1: TriAngle と TriAngleTest という 2 つのクラスを作成します。TriAngle クラスはプライベートの底辺と高さを宣言し、プライベート変数にアクセスするためのパブリック メソッドを宣言します。さらに、クラスに必要なコンストラクターを提供します。これらのパブリック メソッドを別のクラスで使用して、三角形の面積を計算します。

演習 2:

(1) Student クラスを定義します。これには 4 つの属性があります。

String name; 
int age; 
String school; 
String major;

(2) Student クラスの 3 つのコンストラクターを定義します。

第一个构造器Student(String n, int a)设置类的name和age属性;
第二个构造器Student(String n, int a, String s)设置类的name, age 和school属性;
第三个构造器Student(String n, int a, String s, String m)设置类的name, age ,school和major属性;

(3) mainメソッドでは、それぞれ別のコンストラクタで作成したオブジェクトを呼び出し、その属性値を出力します。

演習 3: Account という名前のクラス シミュレーション アカウントを作成します。このクラスのプロパティとメソッドを次の図に示します。このクラスには、属性: アカウント ID、残高残高、年利 AnnualInterestRate、含まれるメソッド: アクセサー メソッド (ゲッター メソッドおよびセッター メソッド)、引き出しメソッドdrawal()、入金メソッドdeposit()が含まれます。
ここに画像の説明を挿入します
ヒント: 出金方法では、ユーザーの残高が出金要件を満たしているかどうかを判断する必要があり、満たしていない場合は、プロンプトが表示されます。

创建 Customer 类。
ここに画像の説明を挿入します

  1. firstName、lastName、account という 3 つのプライベート オブジェクト プロパティを宣言します。
  2. オブジェクトのプロパティを表す 2 つのパラメーター (f と l) を取るパブリック コンストラクターを宣言します。
  3. オブジェクトのプロパティにアクセスするための 2 つのパブリック アクセサーを宣言すると、メソッド getFirstName および getLastName が対応するプロパティを返します。
  4. setAccount メソッドを宣言して、アカウント プロパティに値を割り当てます。
  5. getAccountメソッドを宣言してアカウントのプロパティを取得します。

テスト プログラムを作成します。 (1) Jane Smith という名前の顧客を作成します。彼は口座番号 1000、残高 2000 元、年利 1.23% の口座を持っています。 (2) ジェーン・スミスの手術。 100 ドルを入金し、960 ドルを引き出します。さらに2000元引き出します。 Jane Smith に関する基本情報を印刷します。

成功存入 :100.0
成功取出:960.0
余额不足,取款失败
Customer [Smith, Jane] has a account: id is 1000, annualInterestRate is 1.23%, balance is 1140.0

11. 段階的な知識の補足

11.1 クラスでの属性割り当てのプロセス

1. クラスの属性のどこで属性に値を割り当てることができますか?

① デフォルトの初期化
② 明示的な初期化
③ コンストラクタ内での初期化
④ 渡す对象.属性 または 对象.方法 属性に値を割り当てる

2. これらのポジションはどのような順序で実行されますか?

順序: ① - ② - ③ - ④

3. 注: 上記の①、②、③はオブジェクト作成プロセス中に 1 回だけ実行されます。 ④ オブジェクトの作成後に実行され、必要に応じて複数回実行できます。

11.2 JavaBean

JavaBean は、Java 言語で書かれた再利用可能なコンポーネントです。レンチと同じように、このレンチもさまざまな場所で使用されます。このレンチは複数の機能も提供し (このレンチをレンチ、ハンマー、こじ開けなどに使用できます)、このレンチはコンポーネントです。いわゆる JavaBean は、次の標準を満たす Java クラスを指します。

  • クラスは公開です
  • パラメーターのないパブリック コンストラクターがあります
  • 属性と、対応する get メソッドと set メソッドがあります。

ユーザーは JavaBeans を使用して、関数、プロセス、値、データベース アクセス、および Java コードで作成できるその他のオブジェクトをパッケージ化できます。また、他の開発者は、内部 JSP ページ、サーブレット、他の JavaBeans、アプレット、またはアプリケーション オブジェクトを通じてこれらを使用できます。ユーザーは、JavaBeans を、いつでも、どこでも、変更を気にすることなく、コピー アンド ペーストの機能を提供すると考えることができます。 「Think in Java」では、JavaBean はもともと Java GUI のビジュアル プログラミングのために実装されたと述べました。 IDE ビルド ツールをドラッグして GUI コンポーネント (複数選択ボックスなど) を作成します。実際、ツールは Java クラスを作成し、変更および調整できるクラスのプロパティを公開し、イベントを公開します。リスナー。例:

public class JavaBean {
    
    
    private String name; // 属性一般定义为private
    private int age;
    public JavaBean() {
    
    
    }
    public int getAge() {
    
    
        return age;
    }
    public void setAge(int a) {
    
    
        age = a;
    }
    public String getName() {
    
    
        return name;
    }
    public void setName(String n) {
    
    
        name = n;
    }
}

11.3 UML クラス図

UML (統一モデリング言語、統一モデリング言語) は、软件模型架构 を記述するために使用されるグラフィック言語です。一般的に使用される UML ツール ソフトウェアには、PowerDesingerRoseEnterprise Architect などがあります。 UMLツールソフトウェアは、ソフトウェア開発に必要なさまざまな図を描画するだけでなく、対応するソースコードを生成することができます。ソフトウェア開発では、UML类图 を使用すると、クラスの内部構造 (クラスの属性と操作) とクラス間の関係 (関連付け、依存関係、集約など) をより直観的に記述することができます。 。

  • + はパブリック型を表し、- はプライベート型を表し、# はプロテクト型を表します
  • メソッド記述:メソッドタイプ(+、-) メソッド名(パラメータ名:パラメータタイプ):戻り値タイプ
  • イタリック体は抽象メソッドまたはクラスを示します。
    ここに画像の説明を挿入します
    ここに画像の説明を挿入します

本日の研究はこれで終わります. 著者はここで, Java言語を学習するより多くの読者が寄り道を避け, 時間を節約できるよう, 学習とコミュニケーションのみを目的として記事を書いていることを宣言します. 他の目的には使用しません. 権利侵害があれば,ブロガーに連絡して削除してください。このブログ記事をお読みいただきありがとうございます。この記事があなたのプログラミングの旅のガイドになれば幸いです。幸せな読書!


ここに画像の説明を挿入します

    良い本は 100 回読んでも飽きません。レッスンを徹底的に読んだ後は自分自身を知ることができます。そして、もし私がこの部屋で一番ハンサムな男になりたいのなら、学習を通じてより多くの知識を獲得することに粘り強く取り組み、知識を使って自分の運命を変え、ブログを使って自分の成長を目撃し、自分の行動で自分が頑張っていることを証明しなければなりません。 。
    私のブログがお役に立ちましたら、私のブログの内容が気に入っていただけましたら、 点赞评论、 < a i=4> ワンクリックで3連打!好きな人は運気が悪くならず、毎日元気に過ごせるそうですよ!本当にタダでセックスしたいのなら、毎日幸せな一日を過ごしてください。頻繁に私のブログにアクセスしてください。 收藏
 コーディングは簡単ではありませんが、皆さんのサポートが私の原動力です。 关注 私を好きになることを忘れないでください!

おすすめ

転載: blog.csdn.net/xw1680/article/details/134323940