Mad Theology Java ゼロベーシック学習ノート

Java フルスタックへの取り組みについて、Kuangshen 氏に深く感謝します。
ビデオ アドレス: https://www.bilibili.com/video/BV12J41137hu?p=1

Javaのインストール

こんにちは世界

JDK 11 バージョンのインストール後 (Baidu は、これまでの JDK 8 の代わりに、2020 年頃に JDK 11 の使用を開始します)

Notepad++ で次のコードを記述し、helloworld.java として保存すると、儀式用の helloworld が埋め込まれます。

public class helloworld{
    
    
	public static void main(String[] args){
    
    
		System.out.print("Hello,World!");
	}
}

保存後、フォルダー ディレクトリで cmd コマンド ラインを開始します (ファイル パスの直前に cmd と入力するか、コマンド ラインでファイルの場所に cd するだけです)。

画像の説明を追加してください

Java ランタイムのメカニズム

混合言語のコンパイルと解釈

ここに画像の説明を挿入

IDEAのインストール

ここに画像の説明を挿入

ここに画像の説明を挿入

IDEAのショートカットキー

ここに画像の説明を挿入

新しいプロジェクトを作成した後、Hello World のコードを再度完成させます。今回は、各キーワードの最初の文字であるショートカット キーを使用します。psvm と soout は、以下のコードのブロック全体を表します。

public static void main(String[] args){
    
    } // psvm
System.out.print("Hello,World!");  // sout

Javaの基本構文

1. 注意事項

コメントは他の人が読むためだけではなく、実際にはコードのメモであり、自分自身や他の人が読むのに便利です。

public class HelloWorld {
    
    
    public static void main(String[] args) {
    
    
        // 单行注释
        // 输出一个HelloWorld
        System.out.println("HelloWorld");
        /*
        多行注释
         */
        // JavaDoc:文档注释  /**  */
        /**
         * @description HelloWorld
         * @author Marine
         */
    }
}

このうち、文書コメントの@にはそれぞれ意味があり、一般的に大企業が業務を標準化する際には先頭に記述する必要があります。

2. 識別子

つまり、名前を付けるときに区別する必要がある予約語と識別子は大文字と小文字が区別されます。

すべての識別子は、文字 (AZ または az)、ドル記号 ( )、またはアンダースコア ( ) で始まる必要があります。イニシャルの後には、文字 ( A − Z または a − z )、ドル記号 ( )、またはアンダースコア ( ) を続けることができます。最初の文字の後には、文字 (AZ または az)、ドル記号 () またはアンダースコア( )で始まります最初の文字の後文字( AZまたはaz ) ドル記号( )、アンダースコア ()、または数字の任意の組み合わせを使用できますが、キーワードを変数名またはメソッド名として使用することはできません。

3. データ型

Java は厳密に型指定された言語です。変数の使用は規制に厳密に準拠する必要があるため、使用する前に変数を定義する必要があります (強い型にはセキュリティが高いという利点がありますが、比較的遅いです)。

public class Demo02{
    
    
    public static void main(String[] args){
    
    
        String a = "hello";
        int num = 10;
        System.out.println(a);
        System.out.println(num);
    }
}

8 つのデータ型

public class Demo03{
    
    
	public static void main(String[] args){
    
    
	// 八大基本数据类型
	
	// 整数
	int num1 = 10;
	byte num2 = 20;
	short num3 = 30;
	long num4 =40L;
	
	// 小数:浮点数
	float num5 = 50.1F; // float类型要在数字后面加个F
	double num6 = 3.141592653;

	// 字符类型
	char name = 'a'; // 字符指的是一个字母
	// 字符串,String 不是关键字,是一个类
	String namea = "秦疆";
	
	// 布尔型:是非
	boolean flag = true;
	// boolean flag = false;
	}
}

4. データ型の拡張

public class Demo04{
    
    
	public static void main(String[] args){
    
    
	// 整数拓展 进制 二进制以0b开头 八进制以0开头 十进制 十六进制以0x开头
	int num1 = 10; // 十进制10
	int num2 = 010; // 八进制的10 也就是十进制的8
	int num3 = 0x10; // 十六进制的10 也就是十进制的16
	System.out.println(num1); // 10
	System.out.println(num2); // 8
	System.out.println(num3); // 16

	// ======================================================
	// 浮点数拓展
	// 金融公司用 float 和 double 计算钱会有问题
	float f = 0.1f; // 0.1
	double d = 1.0 / 10; // 0.1
	System.out.println(f==d); // false

	// float 表现的字长是有限、离散的 存在舍入误差,只能提供接近但不等于的值
	// 最好避免使用浮点数进行比较
	float f1 = 1212121212121212f;
	float f2 = f1 + 1;
	System.out.println(f1==f2); // false

	// 有一个 BigDecimal 数字工具类进行表示
	// ======================================================
	// 字符拓展 所有的字符本质都是数字 编码问题 Unicode 对字母汉字进行编码
	char c1 = ‘a’;
	char c2 = '中';
	System.out.println(c1);
	System.out.println(int(c1)); // 强制转换数据类型到int
	System.out.println(c1);
	System.out.println(int(c1));

	// 转义字符 \t 制表符  \n 换行
	System.out.println(Hello\tWorld!\t”);
	}
}

型変換
Java は厳密に型指定された言語であるため、一部の操作を実行するときに型変換が必要です。

低  ---------------------------------------->  高
byte,short,char -> int -> long -> float -> double

演算では、異なる型のデータを同じ型に変換してから演算を行います(容量が異なるため、範囲が異なります)

public class Demo04{
    
    
   public static void main(String[] args){
    
    
   int i = 128;
   byte b = (byte)i; // 内存溢出 b=-128 因为byte 范围 -128~127
   // 强制转换  高-->低 (类型)变量名  
   // 自动转换  低-->高
   /*
   注意点:
   1.不能对布尔值进行转换
   2.不能把对象类型转换为不相干的类型
   3.把高容量转换到低容量的时候,强制转换
   4.转换的时候可能存在内存溢出,或者精度问题
   */
   System.out.println(===================);
   System.out.println((int)23.7); // 23  将double的23.7转换为int 
   System.out.println((int)-45.89f); // -45  将float的-45.89转换为int

5. 変数

Java 変数は厳密に型指定された言語であり、各変数はその型を宣言する必要があります。Java 変数はプログラム内の最も基本的な記憶単位であり、その要素には変数名、変数の型、スコープが含まれます。その本質はメモリ アドレス名です。

	type varName [=value] [{
    
    , varName[=value]}];
//数据类型 变量名   =	值; 
//可以用逗号隔开来声明多个类型变量,但是不推荐这样做保证程序可读性

変数宣言は完全なステートメントであるため、セミコロンで終わる必要があることに注意してください。

6. 定数

初期化後に定数を変更することはできません。変わらない価値観。

定数は、値が設定された後はプログラムの実行中に値を変更できない特別な変数として理解できます。

final 常量名=值;
final double PI=3.14//常量名一般使用大写字母表示
 
public class Demo09{
    
    
    //修饰符不区分前后位置,其中static和final都是修饰符,使用两种输出结果相同
    static final double PI = 3.14;
    // final static double PI = 3.14;
    public static void main(String[] args){
    
    
        System.out.println(PI);
    }
}

変数の命名規則

  • すべての変数、メソッド、クラス名: 名前を見て意味を理解する
  • クラスメンバー変数、ローカル変数、およびメソッド名: 最初の文字は小文字でキャメルケースになります (最初の単語を除き、次の単語の最初の文字は大文字になります lastName)
  • クラス名: 頭文字の大文字化とキャメルケースの原則
  • 定数: 大文字とアンダースコア MAX_NUM

7. オペレーター

  • 算術演算子: + - * / % ++ –
  • 代入演算子: =
  • 関係演算子: >、<、>=、<=、==、!=、instanceof
  • 論理演算子: &&、||、!
  • ビット演算子: &、|、^、~、>>、<<、>>>
  • 条件演算子: ?:
  • 拡張代入演算子: +=、-=、*=、/=
package baseDemo;

public class demo02 {
    
    
    public static void main(String[] args) {
    
    
        // 一元运算符:自增 ++ 自减 --
        int a = 3;
        int b = a++; // a++ 是先赋值后自增,所以此时b=3,语句结束后a=4
        System.out.println(a); // 4
        int c = ++a; // 推荐使用++a 是先自增后赋值,所以赋值前a=5, c=5

        System.out.println(a); // 5
        System.out.println(b); // 3
        System.out.println(c); // 5

        // 幂运算,等需要使用 Math 工具类进行运算
        double power = Math.pow(2, 3);
        System.out.println(pow);
    }
}
package baseDemo;

public class demo03 {
    
    
    public static void main(String[] args) {
    
    
        // 逻辑运算:与或非
        boolean a = true;
        boolean b = false;

        System.out.println("a && b: " + (a && b)); // 两个都为真才为真
        System.out.println("a || b: " + (a || b)); // 两个为假才为假
        System.out.println("!(a && b): " + (!(a && b)));
    }
}

/*
a && b: false
a || b: true
!(a && b): true
Process finished with exit code 0
*/

パッケージのメカニズム - フォルダーに似ています

クラスをより適切に編成するために、Java はクラス名の名前空間を区別するためのパッケージ メカニズムを提供します。
パッケージ ステートメントの構文形式は次のとおりです。

package com.kuangstudy.www // 用 . 隔开各个层级文件夹

一般に、会社のドメイン名はパッケージ名として反転されます。場合によっては、特定のパッケージのメンバーを使用するために、そのパッケージを Java プログラムに明示的にインポートする必要があります。import ステートメントを使用するだけです。

import com.kuangstudy.* //  .* 是通配符表示该层级下所有文件

JavaDoc

javadoc コマンドは、独自の API ドキュメントを生成するために使用されます。

  • @author 著者名
  • @version バージョン番号
  • @since は必要な最も古い JDK バージョンを示します
  • @paramパラメータ名
  • @return 戻り値の場合
  • @throws 例外スロー条件

Java フロー制御

1. スキャナーオブジェクト

java.util.Scanner は Java5 の新機能であり、Scanner クラスを通じてユーザー入力を取得できます。

Scanner s = new Scanner(System.in);

入力文字列は、Scanner クラスの next() および netxLine() メソッドを通じて取得されます。通常、読み取る前に、hasNext() および hasNextLine() を使用して、入力データがあるかどうかを確認する必要があります。

package scanner;

import java.util.Scanner;

public class Demo01 {
    
    
    public static void main(String[] args) {
    
    
        // 创建一个扫描对象,用于接受键盘数据
        Scanner scanner = new Scanner(System.in);
        System.out.println("使用next方式接受:");

        // 判断用户有没有输入字符串
        if (scanner.hasNext()){
    
    
            // 使用next方式接受
            String str = scanner.next();
            System.out.println("输出的内容为:" + str );
        }

        // 关闭 Scanner ,解除 IO 流资源占用
        scanner.close();
    }
}

// 输出界面如下
使用next方式接受:
hello world		
输出的内容为:hello		
// 由于使用的是 scanner.next() 一次读入一个单词以空格划分,若使用 scanner.nextLine() 则是 hello world

Process finished with exit code 0

next() メソッド:

  1. 入力を終了する前に、必ず有効な文字を読んでください。
  2. 有効な文字を入力する前に空白が見つかった場合、 next() メソッドはそれらを自動的に削除します。
  3. 有効な文字が入力された場合にのみ、その後の空白が区切り文字または終了文字として使用されます。
  4. next() はスペースを含む文字列を取得できません

nextLine():

  1. Enter で終了します。つまり、 nextLine() メソッドは、復帰に入る前のすべての文字を返します。
  2. 空白になる可能性があります
package scanner;

import java.util.Scanner;

public class Demo01 {
    
    
    public static void main(String[] args) {
    
    
        // 创建一个扫描对象,用于接受键盘数据
        Scanner scanner = new Scanner(System.in);
        // 计算数值的和
        double sum = 0;
        // 计算有多少个数
        int count = 0;
        System.out.println("使用next方式接受:");

        // 通过循环判断是否还有输入,并在里面对每一次进行求和统计
        while(scanner.hasNextDouble()){
    
    
            double num = scanner.nextDouble(); // 读取数字赋值给中间变量 num
            count++; // 将计数器加1
            sum += num;
        }

        System.out.println(count + "个数的和为" + sum);
        System.out.println(count + "个数的平均值是" + (sum / count));

        // 关闭 Scanner ,解除 IO 流资源占用
        scanner.close();
    }
}

// 输出界面如下
使用next方式接受:
10
20
30
40
x		// 输入不是 double 类型时才会推出循环
4个数的和为100.0
4个数的平均值是25.0

Process finished with exit code 0

2. シーケンシャル構造

Java の基本構造はシーケンシャル構造であり、特に指定がない限り、文ごとに順番に実行されます。シーケンス構造は最も単純なアルゴリズム構造であり、ステートメントとステートメントの間で、上から下へ順番に実行され、順番に実行されるいくつかの処理ステップで構成され、どのアルゴリズムとも切り離せない種類のアルゴリズムの基本構造です。

3. 構造を選択する

  • if 単一選択構造: 多くの場合、何かを実行する前に実行可能かどうかを判断する必要があります。そのようなプロセスは、プログラム内の if ステートメントによって表されます。
if(布尔表达式){
    
    
    // 如果布尔表达式为 true 将执行的语句
}
// 如果布尔表达式为假则直接跳过 if(){} 语句,执行下一个语句
package structure;

import java.util.Scanner;

public class ifDemo {
    
    
    public static void main(String[] args) {
    
    
        Scanner scanner = new Scanner(System.in);

        System.out.println("请输入内容:");
        String s = scanner.nextLine(); // 读取一行输入给 s

        // equals:判断字符串是否相等
        if (s.equals("Hello")){
    
    
            System.out.println(s);
        }

        System.out.println("End");
        scanner.close();
    }
}

// 输出界面如下
请输入内容:
Hello
Hello
End

Process finished with exit code 0
  • 二重選択構造の場合 - 2 つのうち 1 つを選択します
if(布尔表达式){
    
    
    // 如果布尔表达式为 true 将执行的语句
}
else{
    
    
    // 如果布尔表达式为 false 将执行的语句
}
package structure;

import java.util.Scanner;

public class ifDemo {
    
    
    public static void main(String[] args) {
    
    
        // 考试分数大于60就是及格,小于60就是不及格

        Scanner scanner = new Scanner(System.in);

        System.out.println("请输入成绩:");
        int score = scanner.nextInt(); // 读取成绩给 score

        // equals:判断字符串是否相等
        if (score >= 60){
    
    
            System.out.println("恭喜你及格了,成绩为" + score + "分");
        }
        else{
    
    
            System.out.println("很抱歉,你挂科了,成绩为" + score + "分");
        }
        System.out.println("End");
        scanner.close();
    }
}

// 输出界面如下
请输入成绩:
80
恭喜你及格了,成绩为80End

Process finished with exit code 0
  • if 複数選択構造 - ステートメントのうち 1 つだけを実行でき、他のステートメントは直接スキップされます。
if(布尔表达式1){
    
    
    // 如果布尔表达式1为 true 将执行的语句
}
else if(布尔表达式2){
    
    
    // 如果布尔表达式2为 true 将执行的语句
}
else if(布尔表达式3){
    
    
    // 如果布尔表达式3为 true 将执行的语句
}
else if(布尔表达式4){
    
    
    // 如果布尔表达式4为 true 将执行的语句
}
...
package structure;

import java.util.Scanner;

public class ifDemo {
    
    
    public static void main(String[] args) {
    
    
        // 考试分数大于60就是及格,小于60就是不及格

        Scanner scanner = new Scanner(System.in);

        System.out.println("请输入成绩:");
        int score = scanner.nextInt(); // 读取成绩给 score

        // equals:判断字符串是否相等
        if (score==100){
    
    
            System.out.println("恭喜你是满分");
        }
        else if(score < 100 && score >=90){
    
    
            System.out.println("恭喜你成绩是A");
        }
        else if(score < 90 && score >=80){
    
    
            System.out.println("恭喜你成绩是B");
        }else if(score < 80 && score >=70){
    
    
            System.out.println("恭喜你成绩是C");
        }else if(score < 70 && score >=60){
    
    
            System.out.println("恭喜你成绩是D");
        }else if(score < 60 && score >=0){
    
    
            System.out.println("很遗憾你不及格");
        }
        else{
    
    
            System.out.println("输入不合法,请重新输入成绩(整数):");
        }
        System.out.println("End");
        scanner.close();
    }
}



// 输出界面如下
请输入成绩:
65
恭喜你成绩是D
End

Process finished with exit code 0

知らせ

  1. if ステートメントには多くても 1 つの else ステートメントがあり、else ステートメントは他のすべての if ステートメントの後に続きます
  2. if ステートメントには、else ステートメントの前に複数の else if ステートメントを含めることができます。
  3. else if ステートメントの 1 つが true として検出されると、他の else if ステートメントと else ステートメントは実行をスキップします。

4. 複数選択構造の切り替え

複数選択ステートメントを実装するもう 1 つの方法は、switch case ステートメントです。switch case ステートメントは、変数が一連の値の中の特定の値に等しいかどうかを判断します。各値は分岐と呼ばれます。

switch(expression){
    
    
    case value : // value 的变量类型可以是 byte、short、int 或者 char,现在可以比较字符串 String 了
        // 语句
        break; // 可选
    case value :
        // 语句
        break; // 可选
        // 你可以有任意数量的case语句
    default : // 可选
        // 语句
}
...

標準を作成します。侵入や過剰なステートメントの実行を防ぐために、各 case ステートメントの後にブレークを追加します。

package structure;

public class switchDemo {
    
    
    public static void main(String[] args) {
    
    
        // switch 匹配一个具体的值
        char grade = 'C';

        switch (grade){
    
    
            // case 穿透会从第一个匹配分支依次执行每个 case 直到遇到 break 或者 default
            case 'A':
                System.out.println("优秀");
                break; //可选
            case 'B':
                System.out.println("良好");
            case 'C':
                System.out.println("及格");
            case 'D':
                System.out.println("再接再厉");
            case 'E':
                System.out.println("不及格");
            default:
                System.out.println("重新输入");
        }
    }

}

// 输出界面如下
及格
再接再厉
不及格
重新输入

Process finished with exit code 0

5. while ループの構造

  • while は最も基本的なループであり、その構造は次のとおりです。
while( 布尔表达式 ){
    
    
    // 循环内容
}
  • ブール値が true である限り、ループは実行され続けます。
  • ほとんどの場合、ループを停止しますが、ループを終了するには式を無効にする方法が必要です。
  • サーバーリクエストの応答監視など、少数のケースをループで実行する必要があります。
  • ループ条件が常に true の場合、無限ループが発生します。
package structure;

public class whileDemo {
    
    
    public static void main(String[] args) {
    
    
        // 输出1~100

        int i = 0;
        // 每次循环都是先进行判断,表达式为 true 才执行循环体,如此往复
        while(i<100){
    
    
            i++;
            System.out.println(i);
        }
    }
}

6. while ループを実行する

  • while 文の場合、条件が満たされない場合はループに入ることができません。ただし、条件が満たされない場合でも、少なくとも 1 回は実行する必要がある場合があります。
  • do while ループは while ループと似ていますが、do while ループは少なくとも 1 回実行される点が異なります。
  • while と do while の違い: while は最初に判断してから実行し、do while は最初に実行してから判断します。do while は常にループ本体が少なくとも 1 回実行されることを保証します。
do{
    
    
    // 代码语句
}while(布尔表达式);

7.forループ

for ループを使用すると、ループ構造が単純になります。for ループは、反復をサポートする一般的な構造です。最も効率的かつ柔軟です。for ループの実行回数は、実行前に決定されます。形式は次のとおりです。

for(初始化; 布尔表达式;更新){
    
    
    // 循环体
}
100.for // 快捷键 IDEA直接转化成100次的for循环,这是一种快捷方法,前面100可以改成任意数字

for(int i = 0; i < 100; i++) {
    
    
    
}

for(;;i++){
    
     // 死循环
    
}

[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-whn4DKNb-1633524465713)(.\Markdown_picture\for.100.png)]

最初に初期化手順が実行されます。型を宣言できますが、1 つ以上のループ制御変数を初期化できます。もちろん、空のステートメントにすることもできます (既存の変数をループ制御変数として使用)。その後、ブール式の値がチェックされます。 。true の場合、ループ本体が実行されます。false の場合、ループは終了し、ループ本体はスキップされて次のステートメントが実行されます。ループ本体が一度実行された後、ループ制御変数が更新され、ブール式が再度チェックされ、上記のプロセスが循環的に実行されます。

package structure;

public class forDemo {
    
    
    public static void main(String[] args) {
    
    
        // 练习:计算0-100之间奇数和偶数的和
        int sumOdd = 0; // 奇数和
        int sumEven = 0; // 偶数和
        for(int i = 0; i <= 100;i++){
    
    

            if((i%2)==0){
    
     // 通过取余判断奇偶性,是偶数则对偶数和迭代
                sumEven = sumEven + i;
                System.out.println(i+"是偶数");

            }
            else{
    
     // 不满足偶数的 i 就是奇数了,更新奇数和
                sumOdd = sumOdd + i;
                System.out.println(i+"是奇数");
            }
        }
        System.out.println("偶数和为" + sumEven);
        System.out.println("奇数和为" + sumOdd);
    }
}

// 输出界面如下
......
99是奇数
100是偶数
偶数和为2550
奇数和为2500

Process finished with exit code 0
package structure;

public class forDemo {
    
    
    public static void main(String[] args) {
    
    
        // 练习:用 for 循环输出1-1000之间能被5整除的数,并且每行输出3个
        int count = 0; // 初始化输出计数变量为0
        for(int i = 1; i <= 1000;i++){
    
    
            if((i%5)==0){
    
     // 通过取余判断能否被5整除,只输出能被5整除的数
                // 控制每行输出3个数,新增一个计数变量 count,每当 count 被3整除时输出换行符
                count++;
                if(count%4 == 0){
    
     // 余数为1,2,3时输出,为0时输出空行
                    System.out.println(); // 每隔3个数输出一个空行
                }
                else{
    
    
                    System.out.print(i+"\t");
                }
            }
        }
    }
}

// 输出界面如下
......
945 950 955 
965 970 975 
985 990 995 

Process finished with exit code 0

ここに画像の説明を挿入

package structure;

public class forDemo {
    
    
    public static void main(String[] args) {
    
    
        // 练习:打印九九乘法表

        for(int i = 1; i <= 9;i++){
    
     // 外层循环9次,循环控制变量 i 同时作为右乘数
            for(int j = 1; j <= i; j++){
    
     // 内层循环 j 次,循环控制变量 j 同时作为左乘数,j <= i形成下三角的乘法表
                System.out.print(j+"x"+i+"="+(i*j)+"\t"); // 输出乘法公式 i x j = i*j
            }
            System.out.println(); // 每一行执行完后换行
        }
    }
}

// 输出界面如下
1x1=1	
1x2=2	2x2=4	
1x3=3	2x3=6	3x3=9	
1x4=4	2x4=8	3x4=12	4x4=16	
1x5=5	2x5=10	3x5=15	4x5=20	5x5=25	
1x6=6	2x6=12	3x6=18	4x6=24	5x6=30	6x6=36	
1x7=7	2x7=14	3x7=21	4x7=28	5x7=35	6x7=42	7x7=49	
1x8=8	2x8=16	3x8=24	4x8=32	5x8=40	6x8=48	7x8=56	8x8=64	
1x9=9	2x9=18	3x9=27	4x9=36	5x9=45	6x9=54	7x9=63	8x9=72	9x9=81	

Process finished with exit code 0

拡張された for ループ

主に配列とコレクションを走査するために使用され、後で頻繁に使用されます。

for(声明语句 : 表达式){
    
     
    // 代码语句
}
  • 宣言ステートメント: 新しいローカル変数を宣言します。変数の型は配列要素の型と一致する必要があり、スコープはループ ステートメント内で制限され、その値はこの時点の配列要素の値と等しくなります。
  • 式: 式は、アクセスする配列の名前、または配列を返すメソッドです。
package structure;

public class forDemo {
    
    
    public static void main(String[] args) {
    
    
        int[] numbers = {
    
    10,20,30,40,50}; // 定义了一个数组
        // 遍历数组的元素 迭代器
        for(int x:numbers){
    
    
            System.out.println(x);
        }
    }
}

// 输出界面如下
10
20
30
40
50

Process finished with exit code 0

継続を中断する

  • Break ループ ステートメントの本体で、break を使用してループの流れを制御できます。Break は、ループ内の残りのステートメントを実行せずにループを強制的に終了するために使用されます(ループ本体全体からジャンプします)。
  • continue 文は、ループ文本体内で、あるループ処理を終了する、つまりループ本体内でまだ実行されていない文から抜け出して、次回ループを実行するかどうかを決定するために使用されます(1 回のみ。ループの反復はスキップされます)
package structure;

public class forDemo {
    
    
    public static void main(String[] args) {
    
    
        // 打印三角形 5行
        for (int i = 1; i <= 5; i++) {
    
     // 先分解为5行,每一行先输出(5-i)个空格和 2i 个*
            int count = 5 - i; // 每一行的空格数目
            for (int j = 0; j < count; j++) {
    
     // 先输出空格
                System.out.print(" ");
            }
            for (int k = 1; k <= (2*i-1); k++) {
    
     // 再输出星星
                System.out.print("*");
            }
            System.out.println(); // 换行
        }
    }
}

// 输出界面如下
    *
   ***
  *****
 *******
*********

Process finished with exit code 0

Javaメソッド

1.その方法は何ですか?

  • sout-> System.out.println() の具体的な意味は何ですか? このうち、System はクラスなので、System.out は実際には System クラスの標準出力オブジェクトであり、最後に println() はオブジェクトに属し、通常はクラス内で定義されるメソッドです。
  • メソッドは、一緒に機能を実行するステートメントのコレクションです。メソッドは、あるクラスの問題を解決するための手順の順序付けられた組み合わせです。メソッドはクラスまたはオブジェクトに含まれ、プログラム内で作成され、他の場所で参照されます。
  • 設計手法の原理: メソッドの本来の意味は、ある機能を実現するステートメントブロックの集合であるファンクションブロックです。メソッドを設計するときは、メソッドのアトミック性を維持することが最善です。つまり、メソッドは 1 つの関数のみを完了し、後の拡張に役立ちます。
package method;

public class demo01 {
    
    
    // main 方法只是一个致敬,并不是必须从main函数开始执行
    public static void main(String[] args) {
    
    
        int sum = add(5,4);
        System.out.println(sum);

    }
    public static int add(int a, int b){
    
     // static的目的是使add变成全局作用域
        return a+b;
    }
}

2. メソッドの定義と呼び出し

メソッド定義

Java メソッドは他の言語の関数に似ています。これらは、特定の関数を完了するために使用されるコードの断片です。一般に、メソッドの定義には次の構文が含まれます。

メソッドはメソッド ヘッダーとメソッド本体で構成されます。

修饰符 返回值类型 方法名(参数类型 参数名...){
    
    
    ...
    方法体
    ...
    return 返回值;
}

メソッドのすべての部分は次のとおりです。

  • 修飾子: オプション。メソッドの呼び出し方法をコンパイラに指示し、メソッドのアクセス タイプを定義します。

  • 戻り値の型: メソッドには戻り値がある場合があります。returnValueType はメソッドの戻り値のデータ型です。一部のメソッドは目的の操作を実行しますが、戻り値がありません。この場合、returnValueType は void になります。

  • メソッド名: メソッドの実際の名前、メソッド名、パラメータ テーブルが合わせてメソッド シグネチャを形成します。

  • パラメータの種類: パラメータはプレースホルダのようなもので、メソッドが呼び出されるときに値がパラメータに渡されます。この値は実パラメータまたは実変数と呼ばれます。パラメータ リストは、メソッドのパラメータのタイプ、順序、および数を指します。パラメータもオプションであり、メソッドにパラメータを含めることはできません。

    仮パラメータ - メソッドが呼び出されたときに実際のパラメータを受け取るためにスタック上に新しく作成されるプレースホルダ。実際のパラメータ - メソッドが呼び出されたときに実際にメソッドに渡されるデータ

  • メソッド本体: メソッド本体には特定の実行ステートメントが含まれ、メソッドの機能が定義されます。

    package method;
    
    public class demo01 {
          
          
        // main 方法只是一个致敬,并不是必须从main函数开始执行
        public static void main(String[] args) {
          
          
            int maxNumber = max(5,4);
            System.out.println(maxNumber);
    
        }
    
        // 两个整数比大小,取最大值
        public static int max(int a, int b){
          
          
            if(a>=b){
          
          
                return a;
            }
            else{
          
          
                return b;
            }
        }
    }
    
    // 输出界面如下
    5
    
    Process finished with exit code 0
    

    メソッド呼び出し

    • メソッド呼び出し: オブジェクト名.メソッド名 (実際のパラメータリスト)

    • Java はメソッドを呼び出す 2 つの方法をサポートしており、メソッドが値を返すかどうかに応じて選択します。

    • ただし、メソッドが値を返す場合、メソッド呼び出しは通常、値として扱われます。例: int 大きい = max(30, 40);

    • メソッドの戻り値が void の場合、メソッド呼び出しはステートメントである必要があります。例: System.out.println("Hello World")

      Java はすべて値渡しであり、参照渡しはありません。

3. メソッドのオーバーロード

  • オーバーロードとは、関数名は同じだがパラメーターが異なるクラス内のメソッドです
  • メソッドのオーバーロードのルール: メソッド名は同じである必要があります。パラメータ リストは異なっていなければなりません。メソッドの戻り値の型は同じでも異なっていても構いません。戻り値の型が異なるだけでは、メソッドのオーバーロードには十分ではありません。
  • 実装理論: メソッド名が同じ場合、コンパイラは呼び出しメソッドのパラメータの数とパラメータの型に応じて 1 つずつ照合し、対応するメソッドを選択します。照合に失敗した場合、コンパイラはエラーを報告します。

4. コマンドラインパラメータ

プログラムを実行するときに、プログラムにメッセージを渡したい場合があります。これは、コマンド ライン パラメータを main() 関数に渡すことによって実現されます。

package method;

public class commandLine {
    
    
    public static void main(String[] args) {
    
    
        // args.length 数组长度
        for(int i = 0; i < args.length; i++){
    
    
            System.out.println("args["+i+"]"+args[i]);
        }
    }
}
Microsoft Windows [版本 10.0.19043.928]
(c) Microsoft Corporation。保留所有权利。

E:\Study\Windows工作文件\2021.9\Java从零开始\src\method>javac commandLine.java	// 文件夹下面会编译多出一个class文件

E:\Study\Windows工作文件\2021.9\Java从零开始\src\method>cd ..	// 此时必须退回到src文件夹下,因为class文件有依赖关系

E:\Study\Windows工作文件\2021.9\Java从零开始\src>java method.commandLine	// 其实class文件已经运行,只是我们没有给main传参

E:\Study\Windows工作文件\2021.9\Java从零开始\src>java method.commandLine this is shit	// this is shit 被当作2个string参数
args[0]this
args[1]is
args[2]shit

5. 可変パラメータ

  • JDK1.5 以降、Java では同じ型の変数パラメータをメソッドに渡すことがサポートされています。メソッド宣言では、指定されたパラメータ型の後に省略記号 (…) を追加します。

  • メソッド内で指定できる変数パラメータは 1 つだけです。それはメソッドの最後のパラメータである必要があり、通常のパラメータはその前に宣言する必要があります。

  • 配列の詳細

    package method;
    
    public class commandLine {
          
          
        public static void main(String[] args) {
          
          
            commandLine test = new commandLine();
            test.printMax(1,2,5,6,45,222.0);
            }
            public static void printMax(double... numbers){
          
          
            // 健壮性测试
            if(numbers.length == 0){
          
          
                System.out.println("No argument passed");
                return;
            }
    
            double result = numbers[0];
            // 排序
            for(int i = 1; i < numbers.length; i++){
          
          
                if(numbers[i] > result){
          
          
                    result = numbers[i];
                }
            }
            System.out.println("The max value is " + result);
        }
    }
    
    // 输出界面如下
    The max value is 222.0
    
    Process finished with exit code 0
    

6. 再帰

  • 再帰とは次のとおりです。メソッドがメソッドを呼び出します。自分自身に電話してください

  • 再帰を使用すると、単純なプログラムでいくつかの複雑な問題を解決できます。通常、大規模で複雑な問題を層ごとに、元の問題と同様の小規模な問題に変換して解決します。再帰的戦略では、問題解決プロセスに必要な複数の反復計算を記述するために少数のプログラムのみが必要です。プログラム内のコードの量を削減します。再帰の力は、有限ステートメントを使用してオブジェクトの無限のコレクションを定義することにあります。

  • 再帰構造は 2 つの部分で構成されます。

    再帰ヘッダー: 独自のメソッドを呼び出さない場合、ヘッダーがないと無限ループに陥ります

    再帰本体: 独自のメソッドを呼び出す必要がある場合

再帰は基数が小さい場合に使用できますが、基数が大きい場合、関数が呼び出されすぎてスタックが枯渇し、メモリ オーバーフローが発生して実行できなくなります。したがって、再帰ではなく反復メソッドを使用してみてください

package method;

public class demo02 {
    
    
    // 阶乘 n!
    public static void main(String[] args) {
    
    
        System.out.println(func(5)); // 超过50就溢出,结果就是0 
    }
    public static int func(int n){
    
    
        // 递归头提出退出递归的条件:边界条件
        if(n == 1){
    
    
            return 1;
        }else{
    
    
            return n*func(n-1);
        }
    }
}
// 输出界面如下
120

Process finished with exit code 0

package method;

import java.util.Scanner;

// 设计一个计算器,能一直算的那种
public class computer {
    
    
    public static void main(String[] args) {
    
    
        Scanner scanner = new Scanner(System.in); // 读入键盘上的输入
        System.out.println("请输入ENTER进入计算,想结束程序请输入EXIT");
        while(scanner.nextLine()!="EXIT") {
    
    
            System.out.println("请输入第一个整数:");
            int number1 = scanner.nextInt(); // 用于接收键盘上的第一个操作数
            System.out.println("请输入操作符+ - * /");
            String operator = scanner.next();
            System.out.println("请输入第二个整数:");
            int number2 = scanner.nextInt(); // 用于接收键盘上的第二个操作数

            // 主体是Switch结构选择方法
            switch (operator) {
    
    
                case "+":
                    System.out.println(add(number1, number2));
                    break;
                case "-":
                    System.out.println(sub(number1, number2));
                    break;
                case "*":
                    System.out.println(multi(number1, number2));
                    break;
                case "/":
                    System.out.println(div(number1, number2));
                    break;
                default:
                    System.out.println("输入错误!");
            }
        }
        scanner.close();

    }
    public static int add(int a, int b){
    
    
        return a + b;
    }
    public static int sub(int a, int b){
    
    
        return a - b;
    }
    public static int multi(int a, int b){
    
    
        return a * b;
    }
    public static int div(int a, int b){
    
    
        return a / b;
    }
}

Java配列

1. アレイの概要

配列定義

配列は、同じ型のデータ構造の順序付けされたコレクションです。配列は、同じ型の複数のデータを記述し、特定の順序で配置および結合します。各データは配列要素と呼ばれ、各配列要素は通過できます。アイコンをクリックしてアクセスします。

2. 配列宣言の作成

配列変数をプログラムで使用するには、まず配列変数を宣言する必要があります。配列変数を宣言するための構文は次のとおりです。

dataType[] arrayRefVar; // 首选的方法
dataType arrayRefVar[]; // 效果相同,但不是首选的方法

Java 言語は new 演算子を使用して配列を作成します。構文は次のとおりです。

dataType[] arrayRefVar = new dataType[arraySize];

配列の要素はインデックス Index を通じてアクセスされ、配列インデックスは 0 から始まり、配列の長さが取得されます: array.length

メモリ分析

Java メモリ分析:

  1. ヒープ領域: 新しいオブジェクトと配列を格納します。すべてのスレッドで共有でき、他のオブジェクト参照は格納されません。
  2. スタック領域:基本変数型(この基本型の特定の値を含む)、参照オブジェクトの変数(この参照の特定のアドレスをヒープに格納)を格納
  3. メソッド領域: すべてのクラス変数と静的変数を含む、すべてのスレッドで共有できます。

配列の作成処理に対応して、ここでスタック内に取り込みます。

int[] numbers; // 1.声明一个数组,在栈区新建一个“指针”,但没有初始化为随机值,准备指向数组的内存地址
numbers = new int[5]; // 2.创建数组,用 new 给数组在堆区分配了5个 int 的空间,并把地址给到前面的“指针”

numbers[0] = 5; // 3.声明后只能通过下标给数组元素赋值,相当于直接对堆区的每一个 int 空间进行赋值操作
numbers[1] = 15;
numbers[2] = 20;
numbers[3] = 25;
numbers[4] = 30;

ここに画像の説明を挿入

3種類の初期化

静的初期化、動的初期化、配列のデフォルト初期化 (配列は参照型であり、その要素はクラスのインスタンス変数と同等であるため、配列に領域が割り当てられると、その中の各要素もインスタンスと同じ方法で暗黙的に初期化されます)変数)

package array;

public class demo02 {
    
    
    public static void main(String[] args) {
    
    
        // 静态初始化:创建 + 赋值
        int[] a = {
    
    1, 2, 3};
        System.out.println(a[2]);
        // 动态初始化:包含默认初始化
        int[] b = new int[10]; // 此时数组元素均为0
        b[0] = 10;
        System.out.println(b[0]);
        System.out.println(b[1]); // 默认初始化为0
    }
}
// 输出界面如下
3
10
0

Process finished with exit code 0

配列の 4 つの基本特性

  • その長さは固定されており、配列が作成されるとそのサイズは変更できません
  • 配列要素は同じ型である必要があり、型の混合は許可されません
  • 配列内の要素は、プリミティブ型や参照型を含む任意のデータ型にすることができます。
  • 配列変数は参照型に属し、配列もオブジェクトとみなすことができ、配列内の各要素はオブジェクトのメンバ変数に相当します。配列自体はオブジェクトであり、Java のオブジェクトはヒープ内にあるため、配列が元の型を保存するか他のオブジェクト型を保存するかに関係なく、配列オブジェクト自体はヒープ内にあります

配列の境界

添字の有効範囲: [0, length-1]。制限を超えると、エラーが報告されます。 ArrayIndexOutOfBoundsException: 配列添字が範囲外の例外!

概要: 1. 配列は、同じデータ型の順序付けされたコレクションです。 2. 配列はオブジェクトでもあり、配列の要素はオブジェクトのメンバー変数と同等です。 3. 配列の長さは固定され、不変です。制限を超えた場合はエラーが報告されます。

3. 配列の使用

  • for-each ループ

    package array;
    
    public class demo02 {
          
          
        public static void main(String[] args) {
          
          
            int[] arrays = {
          
          1, 2, 3, 4, 5};
            // 遍历打印全部数组元素
            for (int i = 0; i < arrays.length; i++) {
          
          
                System.out.println(arrays[i]);
            }
            System.out.println("===============");
            // 计算所有元素的和
            int sum = 0;
            for (int i = 0; i < arrays.length; i++) {
          
          
                sum += arrays[i];
            }
            System.out.println("数组元素和为:"+sum);
            System.out.println("===============");
            // 查找最大元素
            int max = arrays[0];
            for (int i = 0; i < arrays.length; i++) {
          
          
                if(arrays[i] > max){
          
          
                    max = arrays[i];
                }
            }
            System.out.println("数组最大元素为:"+max);
        }
    }
    // 输出界面如下
    1
    2
    3
    4
    5
    ===============
    数组元素和为:15
    ===============
    数组最大元素为:5
    
    Process finished with exit code 0
    
    package array;
    
    public class demo03 {
          
          
        public static void main(String[] args) {
          
          
            int[] arrays = {
          
          1, 2, 3, 4, 5};
            // JDK1.5开始支持,不用下标使用迭代器遍历数组,和Python一样适合打印但不适合下标操作
            for(int array:arrays){
          
          
                System.out.println(array);
            }
        }
    }
    // 输出界面如下
    1
    2
    3
    4
    5
    
    Process finished with exit code 0
    
  • メソッド入力パラメータとしての配列

    package array;
    
    public class demo03 {
          
          
        public static void main(String[] args) {
          
          
            int[] arrays = {
          
          1, 2, 3, 4, 5};
            // JDK1.5开始支持,不用下标使用迭代器遍历数组,和Python一样适合打印但不适合下标操作
            printArray(arrays);
        }
        // 通过使用方法调用将数组当作参数传入
        public static void printArray(int[] arrays){
          
          
            for(int array:arrays){
          
          
                System.out.println(array);
            }
        }
    }
    // 输出界面如下
    1
    2
    3
    4
    5
    
    Process finished with exit code 0
    
  • 戻り値としての配列

    package array;
    
    public class demo03 {
          
          
        public static void main(String[] args) {
          
          
            int[] arrays = {
          
          1, 2, 3, 4, 5};
            // JDK1.5开始支持,不用下标使用迭代器遍历数组,和Python一样适合打印但不适合下标操作
            printArray(reverseArray(arrays));
        }
        // 打印数组
        public static void printArray(int[] arrays){
          
          
            for(int array:arrays){
          
          
                System.out.println(array);
            }
        }
        // 翻转打印数组
        public static int[] reverseArray(int[] arrays){
          
          
            int[] reverse = new int[arrays.length]; // 新建同样大小数组用于接收原数据
            // 进行元素收尾对调
            for (int i = 0; i < arrays.length; i++) {
          
          
                reverse[arrays.length-i-1] = arrays[i]; //即大小为5的话,r[4]=a[0],记住-1
            }
            return reverse;
        }
    }
    // 输出界面如下
    5
    4
    3
    2
    1
    
    Process finished with exit code 0
    

4. 多次元配列

多次元配列は配列の配列とみなすことができ、たとえば 2 次元配列は各要素が 1 次元配列である特殊な配列です。同様に、多次元配列に拡張でき、入れ子になった配列は次のようになります。

int a[][] = new int[2][5]; // 2行5列的数组,想象成一个链表一样的int[2]是个数组元素是指针指向另一个int[5]的数组首地址

5. 配列クラス

  • 配列のユーティリティ クラス java.util.Arrays。配列オブジェクト自体には呼び出すためのメソッドが宣言されていませんが、API にはユーティリティ クラス Arrays が提供されているので、基本的な操作を実行できます。データオブジェクト。JDK のヘルプ ドキュメントを必ず確認してください。Arrays クラスのメソッドはすべて静的に変更された静的メソッドであり、使用時にクラス名を使用して直接呼び出すことができ、呼び出すオブジェクトを使用しません (注: 必要ではありませんが、不可能ではありません)。

  • 次の共通機能があります。

    配列に値を代入する: fill メソッド

    配列を並べ替える: 並べ替え方法 (昇順)

    配列の比較:equalsメソッド、配列内の要素の値が等しいかどうかを比較します

    配列要素の検索: binarySearch メソッドは、ソートされた配列に対して二分検索を実行できます。

package array;


import java.util.Arrays;

public class demo04 {
    
    
    public static void main(String[] args) {
    
    
        int[] array = {
    
    25, 333, 254, 64, 128};
        // 打印数组元素
        System.out.println(array); // [I@49e4cb85
        // 打印数组元素 Arrays.toString
        System.out.println(Arrays.toString(array));
        // 升序排序
        Arrays.sort(array);
        System.out.println(Arrays.toString(array));
        
        Arrays.fill(array, 20);// 使用20来填充每一个数组元素 
        System.out.println(Arrays.toString(array));
    }
}
// 输出界面如下
[I@49e4cb85
[25, 333, 254, 64, 128]
[25, 64, 128, 254, 333]
[20, 20, 20, 20, 20]

Process finished with exit code 0

バブルソート

バブル ソートは間違いなく最も有名なソート アルゴリズムの 1 つで、合計 8 つのソートがあります。バブル ソートのコードは非常に単純で、2 層のループ ネストがあり、外側の層はバブルの数を記録し、内側の層は最小値を順番に比較します。時間計算量は O(n^2)

package array;

import java.util.Arrays;

public class demo05 {
    
    
    public static void main(String[] args) {
    
    
        int[] a = {
    
    1,5161,11,2457,1346,1846,32,466,55};
        int[] sort = sort(a);
        System.out.println(Arrays.toString(sort));
    }
    // 冒泡排序方法
    public static int[] sort(int[] array){
    
    
        // 外层循环判断走多少次
        for (int i = 0; i < array.length - 1; i++) {
    
    
            // 内层循环比较两个数,每次把最大的数排到最左侧
            for (int j = 0; j < array.length - 1 - i; j++) {
    
    
                // 内层循环比大小,因为外层循环了 i 次所以确定了 i 个数,所以循环次数为 array.length - 1 - i
                if(array[j] < array[j+1]){
    
    
                    // 通过中间杯子交换两个数
                    int temp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = temp; // 相邻两个数组元素交换完毕
                }
            }
        }
        return array;
    }
}
// 输出界面如下
[5161, 2457, 1846, 1346, 466, 55, 32, 11, 1]

Process finished with exit code 0

6. スパース配列

配列内のほとんどの要素が 0 であるか、同じ値の配列である場合、スパース配列を使用して配列を保存できます。スパース配列の処理方法は、配列に行数と列数があり、異なる値がいくつあるかを記録し、異なる値、行、列、値を持つ要素を小規模な配列に記録することで、プログラムのサイズを削減します。

package array;

public class demo06 {
    
    
    public static void main(String[] args) {
    
    
        // 1.创建一个二维数组 11*11 0:没有棋子  1:黑棋  2:白棋
        int[][] array = new int[11][11]; // 新建二维数组,默认值为0
        array[1][2] = 1;
        array[2][3] = 2;
        // 输出原始数组
        System.out.println("输出原始数组:");
        for (int[] ints : array) {
    
    
            for (int anInt : ints) {
    
    
                System.out.print(anInt + "\t");
            }
            System.out.println();// 打印一行后换行
        }
        System.out.println("=========================================");
        // 转换为稀疏数组保存,先获取有效值的个数
        int sum = 0;
        for (int i = 0; i < 11; i++) {
    
    
            for (int j = 0; j < 11; j++) {
    
    
                if(array[i][j] != 0){
    
    
                    sum++;
                }
            }
        }
        System.out.println("有效值的个数:" + sum);

        // 创建一个稀疏数组
        int[][] newArray = new int[sum+1][3];
        newArray[0][0] = 11;// 表头几行几列几个有效值
        newArray[0][1] = 11;
        newArray[0][2] = sum;
        // 遍历二维数组,将非 0 值存放在稀疏数组
        int count = 0;
        for (int i = 0; i < array.length; i++) {
    
    
            for (int j = 0; j < array.length; j++) {
    
    
                if(array[i][j] != 0){
    
    
                    count++; // 计数加换行的作用
                    newArray[count][0] = i; // 先存行号
                    newArray[count][1] = j; // 再存列号
                    newArray[count][1] = array[i][j]; // 再存值大小
                }
            }
        }
        System.out.println("输出稀疏数组:");
        for (int[] ints : newArray) {
    
    
            for (int anInt : ints) {
    
    
                System.out.print(anInt + "\t");
            }
            System.out.println();// 打印一行后换行
        }
    }
}
// 输出界面如下
输出原始数组:
0	0	0	0	0	0	0	0	0	0	0	
0	0	1	0	0	0	0	0	0	0	0	
0	0	0	2	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
=========================================
有效值的个数:2
输出稀疏数组:
11	11	2	
1	1	0	
2	2	0	

Process finished with exit code 0

Java オブジェクト指向プログラミング

Javaの核となる考え方はOOPです

1. オブジェクト指向について知る

  • プロセス指向の考え方: 手順は明確で単純であり、最初のステップで何をすべきか、2 番目のステップで何をすべきかがわかります。プロセス指向は、いくつかの比較的単純な問題に対処するのに適しています。

  • オブジェクト指向の考え方: 物事は群れをなし、分類の考え方。問題を考えると、まずどの分類が必要かという問題が解決され、次にこれらの分類を個別に考えることになります。最後に、プロセス指向は、特定のカテゴリーの下で細部について考えます。オブジェクト指向は、複雑な問題を扱うのに適しており、複数人の協力が必要な問題を扱うのに適しています。

  • 複雑なものを記述する場合、マクロな視点で把握・分析するためには、オブジェクト指向の考え方を用いてシステム全体を分析する必要があります。ただし、特定のマイクロ操作に関しては、依然としてプロセス指向のアプローチが必要です。

    したがって、オブジェクト指向がプロセス指向よりも優れているという意味ではなく、これはディープラーニングと従来のプログラミングと同じですが、問題によってどちらが適しているかが異なります。単純で内容の薄い問題に直面した場合は、プロセス指向でうまく処理できますが、複雑で巨大な問題に直面した場合は、オブジェクト指向の手法を使用して問題を部分に分割することで、混乱せずに良い結果を引き出すことができます。このように、さまざまな特性が集まり、ひとつひとつ分解されていきます。

    プロパティ + メソッド = クラス

オブジェクト指向とは何ですか

  • オブジェクト指向プログラミング (OOP)、オブジェクト指向プログラミングの本質は、コードをクラスの形式で編成し、データをオブジェクトの形式で編成 (カプセル化) することです。

  • 3 つの主な機能: カプセル化 (権限の制限)、継承 (重複の削減)、ポリモーフィズム (複数の形式)

  • 認識論的な観点から見ると、最初にオブジェクトがあり、次にクラスがあります。オブジェクトとは具体的なものです。クラスはオブジェクトを抽象化したものです

  • コード操作の観点から見ると、最初にクラスがあり、次にオブジェクトがあり、クラスはオブジェクトのテンプレートです。

2.手法の見直しと深化

メソッド定義

  • 修飾子: public static はグローバル アクセスを保証します
  • 戻り値の型: 戻り値の型と一致する
  • ブレークとリターンの違い: 1 つは現在のループ本体を終了すること、もう 1 つは現在の関数本体を終了することです
  • メソッド名:ハンプ原理、名前を見れば意味が分かる
  • パラメータリスト: パラメータリスト、パラメータ名
  • 例外スロー: 最後に oop で説明しました

メソッド呼び出し

  • 静的メソッド: static。非常に早い段階でクラスとともにロードされるため、メイン関数で直接呼び出すことができます。
package oop;

public class demo01 {
    
    
    public static void main(String[] args) {
    
    
        Student.say(); // 在静态方法调用时直接用类方法就可以进行调用

    }
}
// 输出界面如下
学生说话了

Process finished with exit code 0
    
package oop;

public class Student {
    
    
    public static void say(){
    
    
        System.out.println("学生说话了");
    }
}
  • 非静的メソッドは、クラスがインスタンス化されたときにのみロードされます。
package oop;

public class demo01 {
    
    
    public static void main(String[] args) {
    
    
        // 对象类型 对象名 = 对象值;
        Student student = new Student(); // 在非静态方法调用时需要实例化对象后调用
		student.say();
    }
}
// 输出界面如下
学生说话了

Process finished with exit code 0
    
package oop;

public class Student {
    
    
    public static void say(){
    
    
        System.out.println("学生说话了");
    }
}

したがって、一方のクラスが静的で、もう一方のクラスが静的でない場合、非静的クラスはまだロードされていないため、相互に呼び出すことはできません。

  • 正式な参加の議論
package oop;

public class demo02 {
    
    
    public static void main(String[] args) {
    
    
      	int a = 1; // 与change方法内 int a 同名不同命,实际是两个内存地址
        System.out.println(a);
        
        demo02.change(a);
		System.out.println(a);
    }
    // 返回值为空,仅进行方法体
    public static void change(int a) {
    
    
        int a = 10; // 作用域有限,仅在方法内有效,方法结束后就被释放了
    }
}
// 输出界面如下
1
1

Process finished with exit code 0

  • 値渡しと参照渡し: 値渡しでは元の値は変更されませんが、参照渡しでは両方の値が変更されます。
package oop;

public class demo02 {
    
    
    public static void main(String[] args) {
    
    
        Person person = new Person(); // 实例化
        System.out.println(person.name);

        demo02.changeName(person);
        System.out.println(person.name);


    }
    public static void changeName(Person a){
    
    
        a.name = "Marine";
    }
}

class Person{
    
    
    String name; // 默认是null
}
// 输出界面如下
null
Marine

Process finished with exit code 0
  • このキーワード

3. オブジェクト作成の分析

クラスとオブジェクトの関係

クラスは抽象データ型であり、特定の種類のものの全体的な説明/定義ですが、特定のものを表すことはできません。これらのクラスは、特定のタイプの特定のものが持つべき特性と動作を記述するために使用されます。

オブジェクトは抽象概念の具体例であり、特性や機能を具体化できるのは抽象概念ではなく具体例です。

オブジェクトの作成と初期化

  • オブジェクトは new キーワードを使用して作成されます

メイン関数クラス (1 つのプログラムで 1 つだけ持つことができます)

package oop.application;

// 一个项目应该只有一个 main 方法
public class Application {
    
    

    public static void main(String[] args) {
    
    
        // 类是抽象的,需要实例化一个个体
        // 类实例化后会返回一个自己类的对象
        Student Jack = new Student(); // 这里的 Student() 其实就是学生类的一个同名构造函数,系统自动生成
        Student Brand = new Student();
        Jack.age = 15;
        Jack.name = "Jack";
        Brand.name = "Brand";
        Brand.age = 16;
        System.out.println(Jack.name+"今年"+Jack.age+"岁");
        System.out.println(Brand.name+"今年"+Brand.age+"岁");
    }
}
// 输出界面如下
Jack今年15Brand今年16Process finished with exit code 0

メンバークラス

package oop.application;

// 学生类
public class Student {
    
    
    // 属性
    String name;
    int age;

    // 方法
    public void study(){
    
    
        System.out.println(this.name + "学生在学习"); // this 代表当前这个类,this.name 则是当前类的name属性
    }

}

  • new キーワードを使用して作成すると、メモリ領域の割り当てに加えて、作成されたオブジェクトがデフォルトで初期化され、クラス内のコンストラクターが呼び出されます。

  • クラス内のコンストラクターはコンストラクターとも呼ばれ、オブジェクトの作成時に呼び出す必要があります。そして、コンストラクターには次の 2 つの特徴があります。

    1. クラス名と同じである必要があります。 2. 戻り値の型がなく、void を記述することはできません。

クラスが何も記述しない場合でも、クラスにはメソッド (構築メソッド) が存在します。もちろん、構築メソッドを明示的に記述して初期値を制限することもできます。

package oop.application;

public class Person {
    
    
    String name;

    // 显示定义无参构造方法
    public Person(){
    
    
        this.name = "Marine"; // 显示赋初始值为 Marine
    }
    // 有参构造方法:一旦定义了有参构造,无参构造就必须显示定义,否则就无效
    public Person(String name){
    
    
        this.name = name; // this.name 的name是对象的属性,而 String name 的name是形参
    }
}
package oop.application;

// 一个项目应该只有一个 main 方法
public class Application {
    
    

    public static void main(String[] args) {
    
    
        // 类是抽象的,需要实例化一个个体
        // 1.使用 new 关键字时,本质是调用构造器
        // 2.初始化值
        Person person = new Person(); 
        System.out.println(person.name); // 此时优先调用用户定义的显示构造方法
    }
}
// 输出界面如下
Marine

Process finished with exit code 0

[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-0C3A6VT6-1633524465715)(.\Markdown_Picture\alt+insert)]

package oop.application;
// 使用 alt + insert 快速添加构造器
public class Person {
    
    
    String name;

    public Person() {
    
    
    }

    public Person(String name) {
    
    
        this.name = name;
    }
}

まとめ

  • コンストラクター: 1. クラス名と同じ 2. 戻り値の型なし
  • 機能: 1. new キーワードを使用する場合、基本はコンストラクターを呼び出すことです。 2. オブジェクトの値を初期化します。
  • 注意点: 1. パラメータ化された構築メソッドを定義した後、パラメータなしの構築メソッドを使用する場合は、定義を表示する必要があります。表示しないと無効になります 2. ショートカット キー ALT + INS、コンストラクタを作成します 3. これは、現在のクラス。クラス定義内でよく使用されます。
    ここに画像の説明を挿入

main関数はスタック領域で動作し、ヒープ領域にはメソッド領域やオブジェクトインスタンス領域などが含まれます。静的メソッド領域は、便宜的に使用している修飾子staticです。クラス内で直接呼び出すことができます。——スタック領域:プログラムが使用、ヒープ領域:プログラマが使用

ここに画像の説明を挿入

実は、main関数内で新たに作成されるオブジェクトは全て参照変数であり、メソッド領域にクラスのメソッド(例えばshout())を継承して呼び出すことで、実際にメモリ上にオブジェクトが存在するヒープ領域が初期化されます。コンストラクター。main 関数内のオブジェクトに対する後続の操作も、ヒープ内の対応するメモリに対する変更となります。

4. オブジェクト指向の3大特徴

カプセル化

  • 隠すべきものは隠すべき

    プログラム設計には**「高凝集性、低結合性」**を追求する必要があります。高い凝集性は、クラスの内部データ操作の詳細がそれ自体で完了し、外部干渉が許可されないことを意味します。低い結合性は、少数のメソッドのみが外部使用に公開されることを意味します。

  • カプセル化(データの隠蔽)

    一般に、オブジェクト内のデータの実際の表現への直接アクセスは禁止されるべきであり、情報隠蔽と呼ばれる操作インターフェイスを通じてアクセスされるべきです。

  • プロパティはプライベートであることに注意してください。get/setは、オープン メソッド get/set を介してクラス内のプライベート プロパティに対して限定された操作のみを実行できます。

package oop.application;

// 学生类
public class Student {
    
    
    // 私有属性
    private String name; // 姓名
    private int ID; // 学号
    private int age; // 年龄
    private char sex; // 性别

    // 提供外部能使用的方法
    // get获得这个数据
    public String getName(){
    
    
        return this.name;
    }
    // set设置这个数据
    public void setName(String name){
    
    
        this.name = name;
    }

}
package oop.application;

// 一个项目应该只有一个 main 方法
public class Application {
    
    

    public static void main(String[] args) {
    
    
        // 类是抽象的,需要实例化一个个体
        Student student1 = new Student();
        System.out.println(student1.getName());
        student1.setName("Marine");
        System.out.println(student1.getName());
    }
}
// 输出界面如下
null
Marine

Process finished with exit code 0

利点: 1. プログラムのセキュリティの向上とデータの保護 2. 隠されたコード実装の詳細 3. 統一されたインターフェース 4. システムの保守性

継承する

継承の本質は、現実世界のより適切なモデリングを実現するために、特定のクラスのグループを抽象化することです。extends は「拡張する」という意味で、サブクラスは親クラスの拡張です。Java のクラスには単一継承のみがあり、多重継承はありません。

継承とはクラスとクラスの関係であり、クラスとクラスの関係には依存関係、合成、集約などが含まれます。継承関係には 2 つのクラスがあり、1 つはサブクラス (派生クラス)、もう 1 つは親クラス (基本クラス) です。サブクラスは、キーワード extends で表される親クラスから継承します。サブクラスと親クラスの間には、ある意味「である」関係が存在する必要があります。

package oop.demo03;

public class Person {
    
    
    public int money = 10_0000_0000; // 财产10亿,属性最好私有get方法访问
    public void say(){
    
    
        System.out.println("Person说了一句话");
    }
}
package oop.demo03;
// 学生 is 人:派生类,子类
// 子类继承了父类,就会拥有父类的全部方法和属性
public class Student extends Person{
    
    
}
package oop.demo03;

public class Application {
    
    
    public static void main(String[] args) {
    
    
        Student student = new Student();
        student.say();
        System.out.println(stuednt.money);
    }
}
// 输出界面如下
Person说了一句话
1000000000
    
Process finished with exit code 0

アクセス許可の 4 つの優先順位は、低から高の順で、パブリック –> プロテクト –> デフォルト –> プライベートです。

ここに画像の説明を挿入

クラス内で CTRL + H を押すと、右側の列に継承ツリー情報が表示されます。デフォルトでは、すべてのクラスが Object クラスを直接または間接的に継承し、いくつかのメソッドが組み込まれています。

素晴らしい

対照的に、this ポインターは現在のクラスを指し、super は現在のクラスの親クラスを指すため、親クラス内の一部の開いているプロパティとメソッドにアクセスできます。

package oop.demo03;

public class Person {
    
    
    protected String name = "Person";
}
package oop.demo03;

public class Student extends Person{
    
    
    public String name = "Student";

    public void test(String name){
    
    
        System.out.println(name); // Marine,形参的值
        System.out.println(this.name); // Student,指向当前类的 name 属性
        System.out.println(super.name); // Person,指向父类的 name 属性
    }
}
package oop.demo03;

public class Application {
    
    
    public static void main(String[] args) {
    
    
        Student student = new Student();
        student.test("Marine");
    }
}
// 输出界面如下
Marine
Student
Person

Process finished with exit code 0

デフォルトでは、サブクラス オブジェクト コンストラクターは最初に親クラス コンストラクターを呼び出します。

package oop.demo03;

public class Person {
    
    
    public Person(){
    
    
        System.out.println("Person无参构造函数");
    }
}
package oop.demo03;

public class Student extends Person{
    
    
    public Student(){
    
    
        // 隐藏代码:调用了父类的无参构造函数
        super(); // super() 默认用来调用父类构造器,必须在子类构造器第一行
        System.out.println("Student无参构造函数");
    }
}
package oop.demo03;

public class Application {
    
    
    public static void main(String[] args) {
    
    
        Student student = new Student();

    }
}
// 输出界面如下
Person无参构造函数
Student无参构造函数

Process finished with exit code 0

超まとめ

  1. super は親クラスのコンストラクターを呼び出します。コンストラクターの最初である必要があります。
  2. super はサブクラスのメソッドまたはコンストラクターにのみ出現する必要があります
  3. super と this を同時にコンストラクターに含めることはできません (両方とも最初の行になければなりません)

対これ:

表現されるオブジェクトは異なります: this は呼び出し元自体のオブジェクトを指します; super は親クラス オブジェクトの参照を指します

前提が異なります。これは継承なしで使用できますが、スーパーは継承の条件下でのみ使用できます。

構築メソッドが異なります。これはこのクラスの構築メソッドを呼び出します。スーパーは親クラスの構築メソッドを呼び出します。

メソッドのオーバーライド

メソッドの書き換えは属性とは関係がなく、メソッドの書き換えは静的メソッドまたは非静的メソッドに関連します。

静的メソッド:

package oop.demo04;

public class A extends B{
    
    
    public static void test(){
    
    
        System.out.println("A=>test()");
    }
}
package oop.demo04;

public class B {
    
    
    public static void test(){
    
    
        System.out.println("B=>test()");
    }
}
package oop.demo04;

public class Application {
    
    
    public static void main(String[] args) {
    
    
        // 方法的调用只和左边,定义的数据类型有关
        A a = new A(); // a 的数据类型是 A
        a.test();
        // 父类的引用可以指向子类
        B b = new A(); // b 的数据类型是 B
        b.test();
    }
}
// 输出界面如下
A=>test()
B=>test()
    
Process finished with exit code 0

非静的メソッド:

package oop.demo04;

public class A extends B{
    
    
    // Override 重写
    @Override // 注解:有功能的注释!
    public void test(){
    
    
        System.out.println("A=>test()");
    }
}
package oop.demo04;

public class B {
    
    
    public void test(){
    
    
        System.out.println("B=>test()");
    }
}
package oop.demo04;

public class Application {
    
    
    
    // 静态方法和非静态方法区别很大!
    public static void main(String[] args) {
    
    
        
        A a = new A(); 
        a.test();
        // 父类的引用可以指向子类
        B b = new A(); // 子类重写了父类的方法
        b.test();
    }
}
// 输出界面如下
A=>test()
A=>test()
    
Process finished with exit code 0

書き換えの概要: 前提として、継承関係があり、サブクラスは親クラスのメソッドをオーバーライドする必要があります。

  1. メソッド名は同じである必要があります
  2. パラメータリストも同じです(そうでない場合はオーバーロードされます)
  3. 修飾子: スコープは拡張可能であり、親クラスのプライベート メソッドからサブクラスのパブリック メソッドまで拡張できます。パブリック –> プロテクト –> デフォルト –> プライベート
  4. スローされる例外: スコープは狭くすることはできますが、広げることはできません。

書き換えるには、サブクラスのメソッド名が親クラスのメソッド名と一致している必要があり、メソッド本体は異なっています。

なぜ書き直す必要があるのでしょうか?親クラスの機能がサブクラスに必要でない可能性があるか、ショートカット キーの ALT + INSERT を使用してオーバーライドを選択することはできません。

多態性

つまり、同じメソッドでも送信オブジェクトに応じてさまざまな動作を採用できます。オブジェクトの実際の型は決定されますが、オブジェクトを指すことができる参照型は多数あります。

ポリモーフィズムが存在する条件: 継承関係があり、サブクラスが親クラスのメソッドをオーバーライドし、親クラスの参照がサブクラスのオブジェクトを指している

注: ポリモーフィズムはメソッドのポリモーフィズムであり、プロパティにはポリモーフィズムはありません。

package oop.demo03;

public class Person {
    
    
    public void run(){
    
    
        System.out.println("run");
    }
}
package oop.demo03;

public class Student extends Person{
    
    
    public void run(){
    
    
        System.out.println("son");
    }
    public void eat(){
    
    
        System.out.println("eat");
    }
}
package oop.demo03;

public class Application {
    
    
    public static void main(String[] args) {
    
    
        // 一个对象的实际类型是不确定的
        // new Student(); new Person();的类型不确定
        // 一个对象的实际类型是确定的,但是指向它的引用类型就不确定了:父类的引用指向子类
        // Student 能调用的方法都是自己的或者继承父类的!
        Student s1 = new Student();
        // Person 属于是父类引用指向了子类,但是不能调用子类独有的方法
        Person s2 = new Student(); // 有继承关系的才行

        s1.run();
        s1.eat();
        s2.run();
        // 对象能执行哪些方法,主要看对象左边的类型,和右边关系不大
        ((Student) s2).eat(); // 子类重写了父类的方法,执行子类的方法必须强制转换
    }
}
// 输出界面如下
son
eat
son
eat

Process finished with exit code 0

ポリモーフィズムに関する注意:

  1. ポリモーフィズムはメソッドのポリモーフィズムですが、プロパティのポリモーフィズムではありません
  2. 親クラスとサブクラスは関連しているためポリモーフィックです。そうでない場合は、型変換例外 ClassCastException!
  3. 既存の条件: 継承関係があり、メソッドを書き直す必要があり、親クラスの参照がサブクラス オブジェクトを指しています。 Father f1 = new Son();

インスタンスの

instanceofは、オブジェクトがどのような型であるか、親子関係があるかObject object = new Student();System.out.println(object instanceof Student);を判断し、そのオブジェクトがStudent型であるかどうかを確認し、trueを返します。

型変換

必須の型変換は、上位から下位の親クラス -> サブクラスにすることができ、float と int の関係と同様に、low から high へ自動的に変換されます。

package oop.demo03;

public class Person {
    
    
    public void run(){
    
    
        System.out.println("run");
    }
}
package oop.demo03;

public class Student extends Person{
    
    
    public void go(){
    
    
        System.out.println("go");
    }
}
package oop.demo03;

public class Application {
    
    
    public static void main(String[] args) {
    
    
        // 高             低
        Person student = new Student();
        // student.go(); 此时 student 对象是 Person 类型,无法调用 Student 类的 go()方法
        // 需要将 Person类型转化为 Student 类型才能使用 Student 类的方法
        ((Student) student).go(); // 带括号强制转换
        // 低             高
        student.run(); // 可以直接使用 Person 类的方法
        
    }
}
// 输出界面如下
go

Process finished with exit code 0

変換の概要: 1. 親クラスの参照は、サブクラス オブジェクトを指します。 2. サブクラスを親クラスに変換し、上向きに変換します。 3. 親クラスをサブクラスに変換し、下向きに変換します - 強制変換 4. 便利なメソッド呼び出しとコードの繰り返しの削減の

抽象化: カプセル化、継承、ポリモーフィズム

ポリモーフィック理解のリファレンス https://www.cnblogs.com/chenssy/p/3372798.html

カプセル化により、クラスの内部実装メカニズムが隠蔽され、使用に影響を与えることなくクラスの内部構造を変更でき、データも保護されます。その内部の詳細は外の世界から隠されており、そのアクセス方法のみが外の世界に公開されています。

継承とは、親クラスのコードを再利用することです。2 つのクラス間に IS-A 関係がある場合、継承を使用できます。同時に、継承はポリモーフィズムの実現への道も開きました。では、ポリモーフィズムとは何でしょうか? ポリモーフィズムの実装メカニズムは何ですか? それらを 1 つずつ明らかにしていきますので、ご覧ください。

いわゆるポリモーフィズムとは、プログラム内で定義された参照変数が指す特定の型と、参照変数を介して発行されるメソッド呼び出しがプログラミング中に決定されるのではなく、プログラムの実行中に決定されること、つまり、どの参照が使用されるかが決定されることを意味します。クラスのインスタンス オブジェクトの場合、参照変数によって発行されるメソッド呼び出しは、どのクラスに実装されるメソッドであり、プログラムの実行中に決定する必要があります。このように、ソース プログラム コードを変更せずに、プログラムの実行時に特定のクラスが決定されるため、参照変数をさまざまなクラス実装にバインドでき、これにより、参照によって呼び出される特定のメソッドがそれに応じて変更されます。プログラムコードは、プログラムの実行中にバインドされた特定のコードを変更できるため、プログラムは複数の実行状態を選択できます。これがポリモーフィズムです。

たとえば、あなたはワインの神であり、ワインに目がないとします。ある日、家に帰ると、テーブルの上に白ワインが入ったグラスが数個置いてありましたが、外から見てもどんなワインなのかは分かりません。そうだった。飲んだら建南春、次は五梁益、次は九桂酒… ここでは次のように表現できます。

ワインa = 建南春

ワイン b = 五梁渓

酒c = アルコール入りワイン

ここで示されているのはポリモーフィズムです。Jiannanchun、Wuliangye、および Jiuguijiu はすべてワインのサブカテゴリです。ワインの親カテゴリを通じてのみ異なるサブカテゴリを参照できます。これはポリモーフィズムです。実行中の参照変数が指す特定の変数のみがわかります。インスタンス オブジェクト。

確かに、ポリモーフィズムを理解するには、「上方変換」とは何かを理解する必要があります。継承では、上方変換について簡単に説明しました。文言は次のとおりです。上記の飲酒の例では、ワイン (Win) が親クラス、Jiannanchun (JNC)、Wulianye (WLY)、および Jiuguijiu (JGJ) がサブクラスです。 。次のコードを定義します。

JNC a = 新しい JNC();

このコードの場合、Jiannanchun のオブジェクトをインスタンス化するだけであることが非常に簡単に理解できます。しかし、これはどうでしょうか?

ワイン a = 新しい JNC();

ここでは、このように理解します。ここでは、JNC オブジェクト インスタンスを指す Wine タイプ a が定義されています。JNC は Wine から継承されるため、JNC はWine に自動的にアップグレードできるため、 はJNC インスタンス オブジェクトを指すことができます。これを行うことには非常に大きな利点があります。継承では、サブクラスが親クラスの拡張であることがわかり、親クラスよりも強力な機能を提供できます。親クラスの参照型を定義すると、サブクラスを作成すると、親クラスの共通性を参照できるだけでなく、サブクラスの強力な機能も使用できます。

しかし、上向きの変換にはいくつかの欠点があります。つまり、必然的にいくつかのメソッドや属性が失われ、それらを取得することができなくなります。したがって、親クラス型の参照は、親クラスで定義されているすべてのプロパティとメソッドを呼び出すことができますが、サブクラスにのみ存在するメソッドとプロパティには追いつきません (オーバーライドされ、サブクラスが優先されます)。 。

public class Wine {
    
    
    public void fun1(){
    
    
        System.out.println("Wine 的Fun1...");
        fun2();
    }
    
    public void fun2(){
    
    
        System.out.println("Wine 的Fun2...");
    }
}

public class JNC extends Wine{
    
    
    /**
     * @desc 子类重载父类方法
     *        父类中不存在该方法,向上转型后,父类是不能引用该方法的
     * @param a
     * @return void
     */
    public void fun1(String a){
    
    
        System.out.println("JNC 的 Fun1...");
        fun2();
    }
    
    /**
     * 子类重写父类方法
     * 指向子类的父类引用调用fun2时,必定是调用该方法
     */
    public void fun2(){
    
    
        System.out.println("JNC 的Fun2...");
    }
}

public class Test {
    
    
    public static void main(String[] args) {
    
    
        Wine a = new JNC();
        a.fun1();
    }
}
-------------------------------------------------
Output:
WineFun.....
JNC 的Fun2...

プログラムの実行結果から、a.fun1() は最初に親クラス Wine で fun1() を実行し、次にサブクラス JNC で fun2() を実行していることがわかりました。

分析: このプログラムでは、サブクラス JNC が親クラス Wine のメソッド fun1() をオーバーロードし、fun2()を書き換えます。また、オーバーロードされた fun1(String a) と fun1() は同じメソッドではありません。これは、親クラスのメソッドがclass このメソッドがないと、上方変換後にこのメソッドが失われるため、JNC を実行する Wine 型参照は fun1(String a) メソッドを参照できません。そして、サブクラス JNC が fun2() を書き換えると、JNC を指す Wine 参照が JNC 内の fun2() メソッドを呼び出します。

したがって、ポリモーフィズムについては次のように要約できます。

サブクラスを指す親クラス参照は、上向き変換により、親クラスが所有するメソッドとプロパティにのみアクセスできます。また、サブクラスに存在するが親クラスに存在しないメソッドについては、参照は使用できませんが、負荷の高いメソッドです。サブクラスが親クラスの一部のメソッドをオーバーライドする場合、これらのメソッドを呼び出すときに、サブクラスで定義されているメソッド (動的接続、動的呼び出し) を使用する必要があります

オブジェクト指向の場合、ポリモーフィズムはコンパイル時ポリモーフィズムと実行時ポリモーフィズムに分けられます。このうちポリモーフィズムは編集時に静的であり、主にメソッドのオーバーロードを指します。パラメータ リストに従って異なる関数を区別します。編集後は 2 つの異なる関数になります。実行時にはポリモーフィズムはありません。そして、実行時のポリモーフィズムは動的であり、動的バインディングによって実現され、これをポリモーフィズムと呼びます。

ポリモーフィックな実装

2.1 実現条件

冒頭で、継承がポリモーフィズムの実現に向けて準備を進めていると述べました。サブクラス Child は親クラス Father を継承します。サブクラスを指す親クラス型参照を作成できます。この参照は、親クラス Father オブジェクトとサブクラス Child オブジェクトの両方を処理できます。同じメッセージがサブクラスまたは親に送信される場合class オブジェクトが作成されると、そのオブジェクトは、それが属する参照に応じて異なる動作を実行します。これがポリモーフィズムです。つまり、ポリモーフィズムは、異なるクラスに異なる応答をさせる同じメッセージです。

Java がポリモーフィズムを実現するには、継承、書き換え、上方変換という 3 つの条件が必要です。

  • 継承: ポリモーフィズムでは、継承関係を持つサブクラスと親クラスが存在する必要があります。
  • 書き換え: サブクラスは親クラスのいくつかのメソッドを再定義し、これらのメソッドが呼び出されるときに、サブクラスのメソッドも呼び出されます。
  • 上方変換: ポリモーフィズムでは、サブクラスの参照を親クラスのオブジェクトに割り当てる必要があります。この方法でのみ、参照は親クラスのメソッドとサブクラスのメソッドを呼び出すことができます。

上記の 3 つの条件が満たされた場合にのみ、統一されたロジック実装コードを使用して、同じ継承構造内の異なるオブジェクトを処理し、異なる動作を実現できます。Java の場合、そのポリモーフィック実装メカニズムは原則に従います。スーパークラス オブジェクト参照変数がサブクラス オブジェクトを参照する場合、参照変数の型ではなく、参照されるオブジェクトの型によって、どのメンバー メソッドを呼び出すかが決まりますが、これはメソッドと呼ばれます。メソッドはスーパークラスで定義する必要があります。つまり、メソッドはサブクラスによってオーバーライドされます。

2.2 実現形態

Java には 2 つの形式のポリモーフィズムがあります。継承とインターフェース。

2.2.1. 継承に基づくポリモーフィズム

継承に基づく実装メカニズムは、主に親クラスとその親クラスを継承する 1 つ以上のサブクラスによる一部のメソッドの書き換えに現れ、複数のサブクラスによる同じメソッドの書き換えでは異なる動作を示すことがあります。

public class Wine {
    
    
    private String name;
    
    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public Wine(){
    
    
    }
    
    public String drink(){
    
    
        return "喝的是 " + getName();
    }
    
    /**
     * 重写toString()
     */
    public String toString(){
    
    
        return null;
    }
}

public class JNC extends Wine{
    
    
    public JNC(){
    
    
        setName("JNC");
    }
    
    /**
     * 重写父类方法,实现多态
     */
    public String drink(){
    
    
        return "喝的是 " + getName();
    }
    
    /**
     * 重写toString()
     */
    public String toString(){
    
    
        return "Wine : " + getName();
    }
}

public class JGJ extends Wine{
    
    
    public JGJ(){
    
    
        setName("JGJ");
    }
    
    /**
     * 重写父类方法,实现多态
     */
    public String drink(){
    
    
        return "喝的是 " + getName();
    }
    
    /**
     * 重写toString()
     */
    public String toString(){
    
    
        return "Wine : " + getName();
    }
}

public class Test {
    
    
    public static void main(String[] args) {
    
    
        //定义父类数组
        Wine[] wines = new Wine[2];
        //定义两个子类
        JNC jnc = new JNC();
        JGJ jgj = new JGJ();
        
        //父类引用子类对象
        wines[0] = jnc;
        wines[1] = jgj;
        
        for(int i = 0 ; i < 2 ; i++){
    
    
            System.out.println(wines[i].toString() + "--" + wines[i].drink());
        }
        System.out.println("-------------------------------");

    }
}
OUTPUT:
Wine : JNC--喝的是 JNC
Wine : JGJ--喝的是 JGJ
-------------------------------

上記のコードでは、JNCとJGJがWineを継承してドリンク()メソッドとtoString()メソッドを書き換え、プログラム動作の結果としてサブクラスのメソッドを呼び出してJNCとJGJの名前を出力するというポリモーフィズムの性能を発揮しています。 。さまざまなオブジェクトが同じ動作を実行できますが、それらはすべて独自の実装を通じてそれを実装する必要があり、これは上方変換の恩恵を受けます。すべてのクラスがスーパークラス Object から継承し、toString() メソッドも Object のメソッドであることは誰もが知っています。

Object o = new JGJ();

      System.out.println(o.toString());

出力は Wine : JGJ です。

Object、Wine、および JGJ 間の継承チェーン関係は、JGJ—>Wine—>Object です。したがって、次のように言えます。サブクラスが親クラスのメソッドをオーバーライドする場合、オブジェクト継承チェーンの最後にあるメソッドのみが呼び出されますただし、次のように書いた場合に注意してください。

Object o = new Wine();

System.out.println(o.toString());

このオブジェクトの継承チェーンには JGJ が存在しないため、出力は Null になるはずです。したがって、継承に基づくポリモーフィズムは次のように要約できます: サブクラスを参照する親クラス型の場合、その参照を処理する際、親クラスを継承するすべてのサブクラスに適用されます。同じアクションを実行することによって生成される動作は異なります。も違います。親クラスが抽象クラスの場合、サブクラスは親クラスのすべての抽象メソッドを実装する必要があるため、親クラスのすべてのサブクラスは統一された外部インターフェイスを持つ必要がありますが、内部固有の実装は異なる場合があります。このようにして、トップレベルのクラスによって提供される統一インターフェイスを使用して、このレベルのメソッドを処理できます。

2.2.2. インターフェース実装に基づくポリモーフィズム

継承は、親クラスの同じメソッドをオーバーライドするいくつかの異なるサブクラスによって明示され、その後、インターフェイスを実装し、インターフェイス内の同じメソッドをオーバーライドするいくつかの異なるクラスによって明示されます。インターフェースのポリモーフィズムでは、インターフェースへの参照はインターフェースを実装するクラスを指定したインスタンスプログラムでなければならず、実行時にはオブジェクト参照の実際の型に応じて対応するメソッドが実行されます。

継承は単一継承であり、関連するクラスのグループに対して一貫したサービス インターフェイスのみを提供できます。ただし、インターフェイスは多重継承および多重実装が可能であり、関連または無関係のインターフェイスのグループを使用して結合および拡張でき、一貫したサービス インターフェイスを外部に提供できます。そのため、継承よりも柔軟性に優れています。

staticキーワードの詳しい説明

package oop.demo01;

import oop.demo03.Person;

public class Student {
    
    
    // 静态属性
    private static int age; // 静态变量
    private double score; // 普通变量

    // 静态方法
    // 在同一个类中,普通方法可以调用静态方法,反之则不行,这是加载顺序决定的
    public void run(){
    
    
        System.out.println("run");
        go();
    }

    public static void go(){
    
    
        System.out.println("go");
    }

    public static void main(String[] args) {
    
    
        Student student = new Student();
        System.out.println(student.score); // 普通变量只能通过实例访问
        System.out.println(student.age);

        System.out.println(Student.age); // 静态变量可以通过类访问
    }
}

詳細なコードブロック

package oop.demo01;

public class Person {
    
    
    {
    
    
        // 匿名代码块,第二个执行,可以赋一些初始值
        System.out.println("匿名代码块");
    }
    static{
    
    
        // 静态代码块,第一个执行,但只执行一次
        System.out.println("静态代码块");
    }

    public Person() {
    
    
        System.out.println("构造器");
    }

    public static void main(String[] args) {
    
    
        Person person = new Person(); // 第三个执行
		System.out.println("====================");
        Person person2 = new Person();
    }
}
// 输出界面如下
静态代码块
匿名代码块
构造器
====================
匿名代码块
构造器

Process finished with exit code 0
package oop.demo01;
// 静态导入包,就不用每次都写全称 Math.random() 可以直接写 random()
import static java.lang.Math.random;
public class Test {
    
    

    public static void main(String[] args) {
    
    
        System.out.println(random());
    }
}

注: 最終クラスは定数であり、継承できません。

5. 抽象クラスと抽象インターフェイス

抽象修飾子はメソッドまたはクラスを変更するために使用できます。メソッドが変更された場合、そのメソッドは抽象メソッドになり、クラスが変更された場合、そのクラスは抽象クラスになります。抽象クラスには抽象メソッドが存在しなくてもかまいませんが、抽象メソッドを持つクラスは抽象クラスとして宣言する必要があります。

抽象クラスは new キーワードを使用してオブジェクトを作成することはできません。これはサブクラスが継承できるようにするために使用されます。抽象メソッド。メソッド宣言のみでメソッド実装はありません。サブクラスで実現できるようにするために使用されます。サブクラスが抽象クラスを継承する場合、抽象クラスが実装していない抽象メソッドを長時間実装する必要があります。そうでない場合は、サブクラスも抽象クラスとして宣言する必要があります。

package oop.demo02;

// 抽象类;子类 extends 只能单继承,只有接口可以多继承
public abstract class Action {
    
    

    // 只是一个声明,没有方法体;一种约束,子类帮忙实现
    public abstract void doSomething();
    // 1.不能new这个抽象类,只能考子类去实现它
    // 2.抽象类中可以写普通方法
    // 3.抽象方法必须在抽象类中
    // 优点:抽象出来,提高开发效率
}
package oop.demo02;

// 抽象类的所有方法,继承了它的子类,都必须要实现它的方法;除非它也是抽象类
public class A extends Action{
    
    
    @Override
    public void doSomething() {
    
    

    }
}

インターフェース

  • 通常のクラス: 具体的な実装のみ
  • 抽象クラス: 具体的な実装と仕様 (抽象メソッド) の両方!
  • インターフェース:仕様のみ!自分でメソッドを書くことはできません〜専門的な制約があります!制約と実装の分離:インターフェイス指向プログラミング

インターフェイスは仕様であり、現実世界で「あなたが...であるなら、あなたは...できるはずです」という考えを具体化する定義された一連のルールです。あなたが天使なら空を飛べるはずです。車なら走らなければなりません。インターフェイスの本質は契約であり、私たちの間にある法律と同じように、それが策定された後は全員がそれを遵守します。OO の本質はオブジェクトの抽象化であり、これを最もよく具体化したものはインターフェイスです。なぜ抽象化機能を備えた言語 (C++、Java など) についてのみデザイン パターンについて説明するかというと、デザイン パターンの研究とは、実際には合理的に抽象化する方法だからです。

クラスを宣言するためのキーワードは class 、インターフェイスを宣言するためのキーワードはインターフェイスです

package oop.demo05;

// 接口定义需要的是抽象思维——Java架构师
// interface 关键字定义接口,接口都需要有实现类
public interface UserService {
    
    
    // 接口中定义的所有属性都是常量 public final
    int AGE = 20;
    // 接口中定义的所有方法都是默认抽象的 public static
    void add(String name);
    void delete(String name);
    void update(String name);
    void query(String name);
}
package oop.demo05;

public interface TimeService {
    
    
    void timer();
}
package oop.demo05;

// 实现类通过关键字 implements 对接口类实现
// 实现了接口的类,就需要重写接口中规范的方法
// 利用接口实现了多继承
public class UserServiceImpl implements UserService,TimeService{
    
    
    @Override
    public void add(String name) {
    
    

    }

    @Override
    public void delete(String name) {
    
    

    }

    @Override
    public void update(String name) {
    
    

    }

    @Override
    public void query(String name) {
    
    

    }

    @Override
    public void timer() {
    
    

    }
}

インターフェイスの概要: インターフェイスは次のとおりです。 1. 制約 2. さまざまな人々が実装できるようにいくつかのメソッドを定義します。 3. インターフェイス内のメソッドには、デフォルトでキーワード public abstract があります。 4. インターフェイス内のプロパティには、デフォルトでキーワード public static Final があります。 5.インターフェイスはインスタンス化できません。インターフェイスには構築メソッドがありません。 6. 実装は複数のインターフェイスを実装できます。 7. 実装クラスはインターフェイス内のメソッドを書き直す必要があります。

6. 内部クラス

内部クラスとは、クラスの中にクラスを定義することです。たとえば、クラス A にクラス B が定義されている場合、クラス B はクラス A に対する内部クラス、クラス A はクラス B に対する外部クラスと呼ばれます。内部クラスは、プライベート プロパティなど、通常のクラスでは実行できない外部クラスの一部のものに直接アクセスできます。

package oop.demo06;
// 外部类
public class Outer {
    
    

    private int ID = 10;
    public void out(){
    
    
        System.out.println("这是外部类的方法");
    }

    public class Inner{
    
    
        public void in(){
    
    
            System.out.println("这是内部类的方法");
        }
        // 可以获得外部类的私有属性
        public void getID(){
    
    
            System.out.println(ID);
        }
    }
}
package oop.demo06;

public class Application {
    
    
    public static void main(String[] args) {
    
    
        Outer outer = new Outer();
        // 通过外部类来实例化内部类
        Outer.Inner inner = outer.new Inner();
        inner.getID();
    }
}
// 输出界面如下
10

Process finished with exit code 0
package oop.demo06;
// 外部类
public class Outer {
    
    
    
}

//一个Java类文件中可以有多个class,但是只能有一个public class
//这样就可以在一个文件内测试了
class A{
    
    
    public static void main(String[] args) {
    
    
        
    }
}

例外メカニズム

1. 例外とは何ですか

  • 実際の仕事では、遭遇する状況が完璧であることはあり得ません。例: 作成した特定のモジュールでは、ユーザー入力が要件を満たしていない可能性があります。プログラムは特定のファイルを開く必要があります。このファイルは存在しないか、ファイル形式が間違っている可能性があります。データベースからデータを読み取りたい場合は、はい、プログラムが再度実行されており、メモリまたはハードディスクがいっぱいである可能性があります。
  • ソフトウェアプログラムを実行していると、先ほど述べたような異常な問題が発生する可能性が高く、これを異常と呼びますが、英語では例外を意味する「エクセプション」といいます。これらの例外や例外について、私たちが作成したプログラムは、プログラムをクラッシュさせることなく適切に処理するにはどうすればよいでしょうか。
  • 異常とは、プログラムの動作中に発生するさまざまな予期せぬ事態を指し、プログラムの動作中に発生し、通常のプログラムの実行フローに影響を与えます。

Java 例外処理の仕組みを理解するには、次の 3 種類の例外を理解する必要があります。

  1. チェック例外: 最も代表的なチェック例外は、プログラマが予見できないユーザー エラーや問題によって引き起こされる例外です。たとえば、存在しないファイルを開こうとすると例外が発生しますが、これらの例外はコンパイル時に単純に無視することはできません。
  2. 実行時例外: 実行時例外は、プログラマが回避できる例外です。チェック例外とは対照的に、実行時例外はコンパイル時に無視できます。
  3. エラー ERROR: エラーは例外ではなく、プログラマの制御の及ばない問題です。通常、コード内のエラーは無視されます。たとえば、スタックがオーバーフローするとエラーが発生し、コンパイル時にチェックされません。

Java例外処理フレームワーク

Java は例外をオブジェクトとして処理し、基本クラス java.lang.Throwable をすべての例外のスーパークラスとして定義します。Java API では多くの例外クラスが定義されており、これらはエラーと例外の 2 つのカテゴリに分類されます。

ここに画像の説明を挿入

2. 例外アーキテクチャ

エラー

  • エラー クラス オブジェクトは Java 仮想マシンによって生成およびスローされ、ほとんどのエラーはコード作成者によって実行されるアクションとは何の関係もありません。
  • Java 仮想マシンの操作エラー (Virtual MachineError) では、JVM に操作の継続に必要なメモリ リソースがなくなった場合、OutOfMemoryError が表示されます。これらの例外が発生すると、通常、Java 仮想マシン (JVM) は終了するスレッドを選択します。
  • また、クラス定義エラー (NoClassDefFoundError) やリンク エラー (LinkageError) など、仮想マシンがアプリケーションを実行しようとしたときにも発生します。これらのエラーはアプリケーション プログラムの制御および処理能力の範囲外にあるため追跡できず、そのほとんどはプログラムの実行中に発生することが許されない状態です。

例外

  • Exception ブランチには重要なサブクラス RuntimeException があります (ランタイム例外)。

    ArrayIndexOutOfBoundException (配列の添字が範囲外)

    NullPointerException (ヌルポインタ例外)

    ArithmeticException (算術例外)

    MissingResourceException (リソースがありません)

    ClassNotFoundException (クラスが見つからない) およびその他の例外。これらの例外はチェックされていない例外であり、プログラム内でキャッチして処理するか、処理できないかを選択できます。

  • これらの例外は通常、プログラムの論理エラーによって発生するため、プログラムは論理的な観点からそのような例外を可能な限り回避する必要があります。

  • エラーと例外の違い: エラーは通常、プログラムによって制御および処理できない壊滅的な致命的なエラーです。これらの例外が発生すると、Java 仮想マシン (JVM) は通常、スレッドの終了を選択します。例外は、通常、スレッドを終了できるプログラムです。これらの例外はプログラム内で可能な限り処理する必要があります。

3. Java例外処理機構

例外をスローする; 例外をキャッチする

例外処理の 5 つのキーワード: try、catch、finally、throw、throws

package exception;

public class demo01 {
    
    
    public static void main(String[] args) {
    
    
        int a = 1;
        int b = 0;

        // 类似 if else 结构如果 try 代码块内发生 catch() 内的异常就执行 catch 代码块
        try{
    
    // try 代码块必须;把可能有异常的代码放进去进行监控
            System.out.println(a/b);
        }catch (ArithmeticException e){
    
    // catch 代码块必须;针对可能的异常进行处理()里是想要捕获的类型
            System.out.println("程序出现异常,变量b不能为0");
        }finally {
    
    // finally 代码块非必须;处理善后工作如资源归还关闭服务等,不论有没有出现异常都会执行
            System.out.println("finally");
        }
    }

}
// 输出界面如下
程序出现异常,变量b不能为0
finally

Process finished with exit code 0
package exception;

public class demo01 {
    
    
    public static void main(String[] args) {
    
    
        int a = 1;
        int b = 0;
		// 选中代码 CRTL + ALT + T 可以快捷键编写try catch代码
        // 捕获结构类似 if else 结构可以叠加,从上至下范围越来越大
        try{
    
    
            System.out.println(a/b);
        }catch (Error e){
    
    
            System.out.println("Error");
        }catch(Exception e){
    
    
            System.out.println("Exception");
        }catch(Throwable t){
    
    
            System.out.println("Throwable");
        }
        finally {
    
    
            System.out.println("finally");
        }
    }

}
// 输出界面如下
Exception
finally

Process finished with exit code 0
package exception;

public class demo01 {
    
    
    public static void main(String[] args) {
    
    
        new demo01().test(1,0); // 哪怕方法中没有定义除法运算也会抛出异常
    }

    // 假设这个方法中,处理不了这个异常,方法上抛出异常
    public void test(int a, int b){
    
    
        if( b == 0){
    
     // throw 与 throws 不同
            throw new ArithmeticException(); // 主动抛出异常,一般在方法中使用
        }
    }
}
// 输出界面如下
Exception in thread "main" java.lang.ArithmeticException
	at exception.Test.test(demo01.java:10)
	at exception.Test.main(demo01.java:5)

Process finished with exit code 1

4. カスタム例外

Java の組み込み例外クラスを使用すると、プログラミング中に発生するほとんどの例外を記述することができますが、その前に、ユーザーは例外をカスタマイズすることもできます。ユーザー定義の例外クラスは、Exception クラスを継承するだけで済みます。

プログラム内でカスタム例外クラスを使用する手順は、次の手順に大別できます。

  1. カスタム例外クラスを作成する
  2. メソッド内の throw キーワードを使用して例外オブジェクトをスローします。
  3. 現在例外をスローしているメソッドで例外が処理される場合は、try-catch ステートメントを使用してそれをキャッチして処理できます。それ以外の場合は、 throws キーワードを使用して、メソッド呼び出しに対してスローされる例外を宣言時に指定します。メソッドを選択し、次のステップに進みます
  4. 例外メソッドの呼び出し元で例外をキャッチして処理します。
package exception;

// 自定义的异常类
public class MyException extends Exception{
    
    

    // 传递数字 > 10;
    private int detail;

    public MyException(int a){
    
    
        this.detail = a;
    }
    // toString:异常的打印信息

    @Override
    public String toString() {
    
    
        return "MyException{" +
                "detail=" + detail +
                '}';
    }
}
package exception;

public class Test {
    
    

    // 可能会存在异常的方法
    static void test(int a) throws MyException {
    
    
        System.out.println("传递的参数为:" + a);

        if( a > 10){
    
    
            throw new MyException(a); // 主动抛出异常,一般在方法中使用
        }
        System.out.println("OK");
    }

    public static void main(String[] args) {
    
    
        try {
    
     // 捕获异常
            test(11);
        } catch (MyException e) {
    
    
            System.out.println("MyException:" + e);;
        }
    }
}
// 输出界面如下
传递的参数为:11
MyException:MyException{
    
    detail=11}

Process finished with exit code 0

5. 実用化におけるまとめ

  • ランタイム例外を処理するときは、ロジックを使用して try-catch 処理を合理的に回避し、支援します。
  • 複数の catch ブロックの後に、見逃される可能性のある例外を処理するために catch (Exception) を追加できます。
  • 不確実なコードの場合は、潜在的な例外を処理するために try-catch を追加することもできます。
  • これに対処してください。単に printStackTrace() を呼び出して出力を印刷することを忘れないでください。
  • 例外を処理する方法は、さまざまなビジネス要件と例外の種類によって異なります。
  • 占有されたリソースを解放するために、finally ステートメント ブロックを追加してみてください。

おすすめ

転載: blog.csdn.net/m0_47455189/article/details/120629412