第一次提交

This commit is contained in:
tensorflow-jumao 2021-07-07 23:51:30 +08:00
parent 3330ba3cea
commit 4bf855c36d
37 changed files with 2763 additions and 9 deletions

View File

@ -0,0 +1,216 @@
# 1. Java简介与安装配置
## 1.1 Java简介
Java是一门面向对象]编程语言不仅吸收了C++语言的各种优点还摒弃了C++里难以理解的多继承、指针等概念因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表极好地实现了面向对象理论允许程序员以优雅的思维方式进行复杂的编程。
## 1.2 Java特性
**1.简单性**
Java看起来设计得很像[C++](https://baike.baidu.com/item/C%2B%2B)但是为了使语言小和容易熟悉设计者们把C++语言中许多可用的特征去掉了这些特征是一般程序员很少使用的。例如Java不支持go to语句代之以提供[break](https://baike.baidu.com/item/break/405784)和[continue](https://baike.baidu.com/item/continue/3009735)语句以及异常处理。Java还剔除了C++的操作符过载***[overload](https://baike.baidu.com/item/overload/5090058)***和多继承特征并且不使用主文件免去了预处理程序。因为Java没有结构数组和串都是对象所以不需要指针。Java能够自动处理对象的引用和间接引用实现自动的无用单元收集使用户不必为存储管理问题烦恼能更多的时间和精力花在研发上。
**2.面向对象**
Java是一个面向对象的语言。对程序员来说这意味着要注意应中的数据和操纵数据的方法*method*,而不是严格地用过程来思考。在一个面向对象的系统中,类***[class](https://baike.baidu.com/item/class/12502737)***是数据和操作数据的方法的集合。数据和方法一起描述对象*object*的状态和行为。每一对象是其状态和行为的封装。类是按一定体系和层次安排的使得子类可以从超类继承行为。在这个类层次体系中有一个根类它是具有一般行为的类。Java程序是用类来组织的。
Java还包括一个类的扩展集合分别组成各种程序包***[Package](https://baike.baidu.com/item/Package)***用户可以在自己的程序中使用。例如Java提供产生图形用户接口部件的类***[java.awt](https://baike.baidu.com/item/java.awt)**包)*这里awt是抽象窗口工具集*abstract windowing toolkit*的缩写,处理输入输出的类***[java.io](https://baike.baidu.com/item/java.io)**包)*和支持网络功能的类***[java.net](https://baike.baidu.com/item/java.net)**包)*。
**3.分布性**
Java设计成支持在网络上应用它是分布式语言。Java既支持各种层次的网络连接又以Socket类支持可靠的流***[stream](https://baike.baidu.com/item/stream)***网络连接,所以用户可以产生分布式的客户机和服务器。
网络变成软件应用的分布运载工具。Java程序只要编写一次就可到处运行。
**4.编译和解释性**
Java编译程序生成字节码*byte-code*而不是通常的机器码。Java字节码提供对体系结构中性的目标文件格式代码设计成可有效地传送程序到多个平台。Java程序可以在任何实现了Java解释程序和运行系统*run-time system*的系统上运行。
在一个解释性的环境中程序开发的标准“链接”阶段大大消失了。如果说Java还有一个链接阶段它只是把新类装进环境的过程它是增量式的、[轻量级](https://baike.baidu.com/item/轻量级/10002835)的过程。因此Java支持快速原型和容易试验它将导致快速程序开发。这是一个与传统的、耗时的“编译、链接和测试”形成鲜明对比的精巧的开发过程。
**5.稳健性**
Java原来是用作编写消费类家用电子产品软件的语言所以它是被设计成写高可靠和稳健软件的。Java消除了某些编程错误使得用它写可靠软件相当容易。
Java是一个强类型语言它允许扩展编译时检查潜在类型不匹配问题的功能。Java要求显式的方法声明它不支持C风格的[隐式声明](https://baike.baidu.com/item/隐式声明)。这些严格的要求保证编译程序能捕捉调用错误,这就导致更可靠的程序。
可靠性方面最重要的增强之一是Java的存储模型。Java不支持指针它消除重写存储和[讹误](https://baike.baidu.com/item/讹误)数据的可能性。类似地Java自动的“无用单元收集”预防存储漏泄和其它有关动态存储分配和解除分配的有害错误。Java解释程序也执行许多运行时的检查诸如验证所有数组和串访问是否在界限之内。
异常处理是Java中使得程序更稳健的另一个特征。异常是某种类似于错误的异常条件出现的信号。使用try/catch/finally语句程序员可以找到出错的处理代码这就简化了出错处理和恢复的任务。
**6.安全性**
Java的存储分配模型是它防御[恶意代码](https://baike.baidu.com/item/恶意代码)的主要方法之一。Java没有指针所以程序员不能得到隐蔽起来的内幕和伪造指针去指向[存储器](https://baike.baidu.com/item/存储器)。更重要的是Java编译程序不处理存储安排决策所以程序员不能通过查看[声明](https://baike.baidu.com/item/声明/13130358)去猜测类的实际存储安排。编译的Java代码中的存储引用在运行时由Java解释程序决定实际存储地址。
Java运行系统使用字节码验证过程来保证装载到网络上的代码不违背任何Java语言限制。这个安全机制部分包括类如何从网上装载。例如装载的类是放在分开的名字空间而不是局部类预防恶意的小应用程序用它自己的版本来代替标准Java类。
**7.可移植性**
Java使得语言声明不依赖于实现的方面。例如Java显式说明每个基本数据类型的大小和它的运算行为*这些数据类型由Java语法描述*。
Java环境本身对新的硬件平台和操作系统是可移植的。Java编译程序也用Java编写而Java运行系统用ANSIC语言编写。
**8.高性能**
Java是一种先编译后解释的语言所以它不如全编译性语言快。但是有些情况下性能是很要紧的为了支持这些情况Java设计者制作了“及时”编译程序它能在运行时把Java字节码翻译成特定[CPU](https://baike.baidu.com/item/CPU)*(中央处理器)*的机器代码,也就是实现全编译了。
Java字节码格式设计时考虑到这些“及时”编译程序的需要所以生成机器代码的过程相当简单它能产生相当好的代码。
**9.多线程性**
Java是多线程语言它提供支持多线程的执行*(也称为轻便过程)*能处理不同任务使具有线索的程序设计很容易。Java的lang包提供一个[Thread](https://baike.baidu.com/item/Thread/5156974)类,它支持开始线索、运行线索、停止线索和检查线索状态的方法。
Java的线索支持也包括一组同步原语。这些原语是基于监督程序和条件变量风范由C.A.R.Haore开发的广泛使用的同步化方案。用关键词[synchronized](https://baike.baidu.com/item/synchronized),程序员可以说明某些方法在一个类中不能并发地运行。这些方法在监督程序控制之下,确保变量维持在一个一致的状态。
**10.动态性**
Java语言设计成适应于变化的环境它是一个动态的语言。例如Java中的类是根据需要载入的甚至有些是通过网络获取的。
## 1.2 Linux环境安装
JDK下载地址
http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
选择 jdk-8uxxx-linux-x64.tar.gz
**解压JDK压缩包**
```
tar zxvf jdk-8uxxx-linux-x64.tar.gz
```
**设置环境变量**
命令行输入
```shell
sudo vim /etc/profile
```
在文件最后,添加如下内容:
```shell
#Java Env
export JAVA_HOME=/usr/你的JDK路径
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export PATH=$PATH:$JAVA_HOME/bin
```
## 1.3 Windows环境安装
### 1.3.1 下载JDK安装包
官网下载https://www.oracle.com/cn/java/technologies/javase/javase-jdk8-downloads.html
![JDK下载的选择](./img/JDK.png)
百度云盘下载的适用于window64位计算机。
百度云盘下载https://pan.baidu.com/s/1LGf3PodzAT1R-7ET1DEOdQ
提取码s6mg
### 1.3.2 安装JDK
直接双击下载好的.exe文件开始安装一般默认安装就好了。
在这里可以更改JDK安装的目录。
![JDK的安装路径](https://user-gold-cdn.xitu.io/2019/9/7/16d07908134c216f?imageView2/0/w/1280/h/960/format/webp/ignore-error/1)
### 3. 配置JAVA环境
JDK安装好之后我们需要为计算机配置JAVA环境。
首先,在计算机中打开环境变量。
打开环境变量的方法有很多种,在这里我用的是点击电脑左下方的搜索功能,直接搜索环境变量就可以打开啦。
![环境变量的打开](C:\Users\83769\Desktop\组队学习\java\img\环境变量的打开.jpg)
打开后,继续点击环境变量:
![打开环境变量](https://user-gold-cdn.xitu.io/2019/9/7/16d079825232e98c?imageView2/0/w/1280/h/960/format/webp/ignore-error/1)
在系统变量中,需要新建一个变量和值。![新增环境变量](C:\Users\83769\Desktop\组队学习\java\img\新增环境变量.png)
1. 配置JAVA_HOME
![JAVA_HOME配置](./img/JAVA_HOME.png)
2. 配置CLASSPATH
`CLASSPATH=.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar`
注意这里变量值的第一个符号必须是**小数点(.)**。
![CLASSPATH配置](./img/CLASSPATH.png)
3. 配置Path
`Path=%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;`
前两者是新建的,这个是在原有上添加,在最后添加时如果前面没有加分号,当前这条前要加分号。
![Path配置](img/20180525150314231)
### 4. 检验安装是否成功
1. 查看java版本
```shell
java -version
```
![查看java版本](img/16d07a85378a48b2)
2. 执行java命令
```shell
java
```
![执行java命令](img/16d07a728bb36516)
3. 执行javac命令
```shell
javac
```
![执行javac命令](img/16d07aa7ab458eec)
## 1.3 开发工具
推荐使用idea安装方式较简单此处略
## 参考文献
[1] 董云铮陈千梅惠平Java技术应用清华大学出版社2007
[2] 李刚疯狂Java讲义第2版电子工业出版社2014
[3] 百度百科 https://baike.baidu.com/item/Java/85979?fr=aladdin#3

View File

@ -0,0 +1,289 @@
# 1.基本数据类型与变量
## 1.1 基本数据类型
Java属于强类型语言强类型语言必须为每一个变量声明一种类型。
Java中基本数据类型也称做简单数据类型包括以下八种
**1、整型**
byte 、short 、int 、long
**2、浮点型**
float 、 double
**3、字符型**
char
**4、布尔型**
boolean
### 1.1.1 整型
**整型byte、short、int、long**
整型数据有四种,它们的取值范围不同
byte 的取值范围:-128127-2的7次方到2的7次方-1
short 的取值范围:-3276832767-2的15次方到2的15次方-1
int 的取值范围:-21474836482147483647-2的31次方到2的31次方-1
long 的取值范围:-92233720368547748089223372036854774807-2的63次方到2的63次方-1
### 1.1.2 浮点型
浮点型包括float和double两种区别在与精度float是单精度、32位、符合IEEE 754标准的浮点数double 数据类型是双精度、64 位、符合 IEEE 754 标准的浮点数。
float单精度浮点型取值范围3.402823e+381.401298e-45
double双精度浮点型取值范围1.797693e+3084.9000000e-324
java对于浮点型数据默认会使用double。
### 1.1.3 字符类型
char 类型是一个单一的 16 位 Unicode 字符;
最小值是 **\u0000**(十进制等效值为 0
最大值是 **\uffff**(即为 65535
char 数据类型可以储存任何字符;
### 1.1.4 布尔类型
布尔类型只有两个取值分别是true 、false 。
java默认是false。
## 1.2 变量
### 1.2.1 变量类型
java属于强类型语言所以变量在使用前必须进行声明以下是几个声明与赋值的示例
```
int a, b, c; // 声明三个int型整数a、 b、c
int d = 3, e = 4, f = 5; // 声明三个整数并赋予初值
byte z = 22; // 声明并初始化 z
String s = "runoob"; // 声明并初始化字符串 s
double pi = 3.14159; // 声明了双精度浮点型变量 pi
char x = 'x'; // 声明变量 x 的值是字符 'x'。
```
java有三类变量分别是
- 类变量:独立于方法之外的变量,用 static 修饰。
- 实例变量:独立于方法之外的变量,不过没有 static 修饰。
- 局部变量:类的方法中的变量。
```java
public class var{
static int lei_var; // 类变量
String str="hello world"; // 实例变量
public void test(){
int local_var =0; // 局部变量
}
}
```
**局部变量**
如果在成员方法中定义一个变量,那么这个变量就被称为局部变量。
局部变量在方法实行时被创建,在方法执行结束的时候被销毁。局部变量在使用时必须进行赋值操作或被初始化,否则出现编译错误。
例如我们创建一个类文件在该类中定义getName()方法在getName()方法中声明int型的局部变量id并赋值为0代码如下
```java
public class BookText(){
public String getName(){
int id = 0; //局部变量,如果我们把初始值去掉,会报错
setName("Java"); //调用类中的其他方法(此类中省略定义方法)
return i + this.name;
}
}
```
==注意:== 类成员变量和成员方法可以统称为类成员。如果一个方法中含有与成员变量同名的局部变量则方法中对这个变量的访问以局部变量的值为基准。例如变量id在 getName()方法中值为0而不是成员变量中id的值。
局部变量的作用域,即局部变量的有效范围,下图描述了局部变量的作用范围。
```java
public void doString(String name){
int id = 0;
for(int i = 0; i< 10; i++)
System.out.println(name + String.valueOf(i));
}
```
在相互不嵌套的作用域中可以同时声明两个名称和类型相同的局部变量,如下图
```java
public void doString(String name){
int id = 0;
for(int i= 0; i<10; i++){
System.out.println(name String.valueOf(i));
}
for (int i= 0; i <3; i++)
System.out.println(i);
}
```
但是在相互嵌套的区域中不可以这样声明如果将局部变量id在方法体的for循环中再次定义编译器将会报错如图所示。
```java
public void doString(String name){
int id = 0;
for(int i= 0; i<10; i++)
System.out.println(name + String.valueOf(i));
for(int i = 0; i<3; i++)
System.out.println(i); int id = 7;
}
```
==注意:== 在作用范围外使用局部变量是一个常见的错误,因为在作用范围外没有声明局部变量的代码。
**实例变量**
也叫类成员变量,声明在一个类当中,方法、构造方法和语句块之外。实例变量的生命周期与对象一致。
**类变量/静态变量**
类变量也称为静态变量,在类中以 static 关键字声明,但必须在方法之外。无论一个类创建了多少个对象,类只拥有类变量的一份拷贝。生命周期与类一致。
### 1.2.2 类型转换
在平时编程的时候,经常需要将一种数值类型转换为另一种数值类型。
![数值类型之间的合法转换](img/i0.hdslb.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg)
- 若两个操作数中有一个是double类型另一个操作数就会转换为double类型
- 若其中一个操作数是float类型另一个操作数也会转换为float类型
- 若其中一个操作数为long类型另一个操作数也会转换为long类型
- 否则两个操作数都会转换为int类型。
数值类型的转换可能会发生精度的丢失例如123456789是一个大整组它所包含的位数比float类型所能表达的位数还要多。当它由整型数值转换为float类型时将会得到同样大小的结果但却丢失一定的精度。
```java
int n = 123456789;
float f = n;
System.out.println(f);
```
输出1.23456792E8
**强制类型转换**
由上方可看出在必要时候int类型会自动转换为double类型而也会有将double类型转换为int类型的需要。这时就需要通过*强制类型转换*来实现这个操作。
强制类型转换的语法格式是在**圆括号中给出想要转换的目标类型,后面紧跟着待转换的变量名**。
```java
double x = 9.997;
int nx = (int)x;
```
在这里变量nx的值就会变成9。强制类型转换通过截断小数部分将浮点值转换为整型。
若想要对浮点数进行舍入运算以便得到最接近的整数就需要用Math.round方法
```java
double x = 9.997;
int nx = (int) Math.round(x);
```
现在变量nx的值为10。
### 1.2.3 常量
常量在程序运行时是不能被修改的。
在 Java 中使用 final 关键字来修饰常量,声明方式和变量类似:
```
final double PI = 3.1415927;
```
虽然常量名也可以用小写,但为了便于识别,通常使用大写字母表示常量。
字面量可以赋给任何内置类型的变量。例如:
```
byte a = 68;
char a = 'A'
```
byte、int、long、和short都可以用十进制、16进制以及8进制的方式来表示。
当使用字面量的时候,前缀 **0** 表示 8 进制,而前缀 **0x** 代表 16 进制, 例如:
```
int decimal = 100;
int octal = 0144;
int hexa = 0x64;
```
和其他语言一样Java的字符串常量也是包含在两个引号之间的字符序列。下面是字符串型字面量的例子
```
"Hello World"
"two\nlines"
"\"This is in quotes\""
```
字符串常量和字符常量都可以包含任何Unicode字符。例如
```
char a = '\u0001';
String a = "\u0001";
```
## 1.3 枚举类型
有时候,变量的取值只在一个有限的集合内,这个变量中很可能保存错误的值。针对这种情况,可以自定义枚举类型。枚举类型包括有限个命名的值。
> 例如:
>
> 销售服装的尺寸有小、中、大和超大四种尺寸。
>
> ```java
> enum Size {SMALL, MEDIUM, LARGE, EXTRA_LARGE};
> //声明这种类型的变量
> Size s = Size.MEDIUM;
> ```
>
> Size类型的变量只能存储这个类型声明中给定的某个枚举值或null值。null表示这个变量没有设置任何值。

48
Java/10.注解.md Normal file
View File

@ -0,0 +1,48 @@
*注释*,一种元数据形式,提供有关程序的数据,该数据不属于程序本身。注释对其注释的代码的操作没有直接影响。
注释有多种用途,其中包括:
- **编译器信息**——**编译器**可以使用注释来检测错误或抑制警告。
- **编译时和部署时处理**——软件工具可以处理注释信息以生成代码、XML 文件等。
- **运行时处理**——一些注解可以在运行时检查。
### 内置的注解
Java 定义了一套注解,共有 7 个3 个在 java.lang 中,剩下 4 个在 java.lang.annotation 中。
**作用在代码的注解是**
- @Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
- @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
- @SuppressWarnings - 指示编译器去忽略注解中声明的警告。
作用在其他注解的注解(或者说 元注解)是:
- @Retention - 标识这个注解怎么保存是只在代码中还是编入class文件中或者是在运行时可以通过反射访问。
- @Documented - 标记这些注解是否包含在用户文档中。
- @Target - 标记这个注解应该是哪种 Java 成员。
- @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)
从 Java 7 开始,额外添加了 3 个注解:
- @SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
- @FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
- @Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。
## 自定义注解
日常开发中我们使用class、interface比较多而注解和它们一样也是一种类的类型他是用的修饰符为 @interface
@元注解
```java
public @interface MyTestAnnotation {
注解属性 [default 默认值]
}
```

169
Java/11.泛型.md Normal file
View File

@ -0,0 +1,169 @@
# 11.泛型
## 11.1 什么是泛型
> 泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
>
> 泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
>
首先来看一个例子
```java
import java.util.ArrayList;
import java.util.List;
public class test {
public static void main(String[] args) {
List list = new ArrayList();
list.add("string");
list.add(100);
for (int i = 0; i < list.size(); i++) {
String name = (String) list.get(i); // 1
System.out.println("name:" + name);
}
}
}
```
上述代码会出现 **Exception in thread "main" java.lang.ClassCastException** 错误
ArrayList由String类型和Integer类型而两者都以String格式使用所以出现了上述错误。
这个时候就用得上泛型了
```java
import java.util.ArrayList;
import java.util.List;
public class test {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("string");
list.add(100);
for (int i = 0; i < list.size(); i++) {
String name = list.get(i); // 2
System.out.println("name:" + name);
}
}
}
```
上述代码会编译错误如果使用idea的话会出现下述错误提示
```
java: 对于add(int), 找不到合适的方法
方法 java.util.Collection.add(java.lang.String)不适用
(参数不匹配; int无法转换为java.lang.String)
方法 java.util.List.add(java.lang.String)不适用
(参数不匹配; int无法转换为java.lang.String)
```
这里通过List\<String\>限定了集合内的元素只能是String类型。
泛型使得代码可以被不同类型的对象重用
## 11.2 泛型方法
下面是定义泛型方法的规则:
- 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前
- 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
- 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
- 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型不能是原始类型像int,double,char的等
```
/**
* 泛型方法的基本介绍
* @param tClass 传入的泛型实参
* @return T 返回值为T类型
* 说明:
* 1public 与 返回值中间<T>非常重要,可以理解为声明此方法为泛型方法。
* 2只有声明了<T>的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。
* 3<T>表明该方法将使用泛型类型T此时才可以在方法中使用泛型类型T。
* 4与泛型类的定义一样此处T可以随便写为任意标识常见的如T、E、K、V等形式的参数常用于表示泛型。
*/
public <T> T genericMethod(Class<T> tClass)throws InstantiationException ,
IllegalAccessException{
T instance = tClass.newInstance();
return instance;
}
```
## 11.3 泛型类
一个泛型类就是拥有一个或者多个类型变量的类。下面看一个简单例子:
```java
ublic class Generic<T>{
//key这个成员变量的类型为T,T的类型由外部指定
private T key;
public Generic(T key) { //泛型构造方法形参key的类型也为TT的类型由外部指定
this.key = key;
}
public T getKey(){ //泛型方法getKey的返回值类型为TT的类型由外部指定
return key;
}
}
```
## 11.4 泛型接口
```
//定义一个泛型接口
public interface Generator<T> {
public T next();
}
```
## 11.5 类型通配符
类型通配符一般是使用?代替具体的类型参数。例如 **List<?>** 在逻辑上是**List<String>,List<Integer>** 等所有List<具体类型实参>的父类。
```
import java.util.*;
public class GenericTest {
public static void main(String[] args) {
List<String> name = new ArrayList<String>();
List<Integer> age = new ArrayList<Integer>();
List<Number> number = new ArrayList<Number>();
name.add("icon");
age.add(18);
number.add(314);
getData(name);
getData(age);
getData(number);
}
public static void getData(List<?> data) {
System.out.println("data :" + data.get(0));
}
}
```

View File

@ -0,0 +1,193 @@
# 2. 运算符和表达式
在Java中使用算术运算符`+、-、*、/`表示加、减、乘、除运算。
当参与`/`运算时,两个操作数都是整数时,表示整除法;否则表示浮点除法。
整数的求余操作(取模)用`%`表示。例如15/2=715%2=115.0/2=7.5。
值得注意,**整数被0除将会产生一个异常而浮点数被0除将会得到无穷大或NaN的结果**。
| 算数运算符 | 说明 |
| ---------- | ------ |
| | 加 |
| | 减 |
| * | 乘× |
| / | 除÷ |
| % | 取余数 |
## 2.1 数学函数与常量
在Math类中包含了各种各样的数学函数在编写不同类别的程序时可能需要的函数也不同。
> 想计算一个数值的平方根可以使用sqrt方法
>
> ```java
> double x = 4;
> double y = Math.sqrt(x);
> System.out.println(y);
> ```
>
> 输出为2.0
在Java中没有幂运算因此需要借助于Math类的pow方法
```java
double y = Math.pow(x, a);
```
将y的值设为x的a次幂($x^a$)。
pow方法有两个double类型的参数其返回结果也为double类型。
> - Math类还提供了常用的三角函数
>
> - Math.sin
>
> - Math.cos
>
> - Math.tan
>
> - Math.atan
>
> - Math.atan2
>
> - 指数函数以及它的反函数自然对数以及10为底的对数
>
> - Math.exp;
> - Math.log;
> - Math.log10;
>
> - 两个用于表示$\pi和e$常量的近似值:
>
> - Math.PI
> - Math.E
如果不想再数学方法名和常量名前添加前缀"Math",只需要在源文件的顶部添加代码:
```java
import static java.lang.Math.*;
```
## 2.2 结合赋值和运算符
可以在赋值中使用二元运算符,这是一种便捷的简写形式:
```java
x += 4;
//等价于
x = x + 4;
```
(一般地,将运算符放在=号的左边,如*=或%=
## 2.3 自增与自减运算符
自增、自减运算符n++将变量n的当前值加1n--将n的值减1。
```java
int n = 12;
n++; //自增后n=13
```
这些运算符只会改变变量的值它们的操作数不能是数值。例如4++是个非法语句。
自增与自减运算符还有一种“前缀”形式:++n--n后缀和前缀形式都会使变量值加1或减1。在表达式中**前缀形式会先完成加1而后缀形式会先使用变量原来的值**。
```java
int m = 7;
int n = 7;
int a = 2 * ++m; // a=16,m=8
int b = 2 * n--; // b=14,n=8
```
## 2.4 关系和boolean运算符
- 要检测**相等性**可以使用两个等号==
```java
3 == 7 //返回false
```
- 检测**不相等**就使用!=
```java
3 != 7 //返回true
```
- 经常使用的运算符还有:<小于>大于,<=小于等于,>=大于等于;
- 感叹号!就是逻辑**非**运算符,运算符&&表示逻辑**“与“**运算符,运算符||表示逻辑**”或“**运算符;
```java
expression1 && expression2
```
expression1和expression2计算返回的结果都为true时整个表达式才会返回true
若expression1和expression2计算返回的结果其中一个为false时整个表达式返回的结果为false。
```java
expression1 || expression2
```
若expression1返回true则不计算expression2将整个表达式的结果返回true
若expression1返回false计算expression2返回true整个表达式结果也将会返回true
若expression1和expression2的返回结果都是false那整个表达式结果也将返回false。
- 三目运算符x?y:z当x返回结果为true时就返回y当x返回结果为false时就返回z。
```java
x < y ? x : y
```
将会返回x和y中较小的一个。
## 2.5 位运算符
处理整数类型时,可以直接对组成整型数值的各个位完成操作。位运算符包括:&("and")、|("or")、^("xor")、~("not")。另外还有>>和<<运算符将位模型左移或右移
## 2.6 括号与运算符级别
运算符优先级:
| 结合性 | 运算符 |
| -------- | ------------------------------------------------------ |
| 从左往右 | ()括号 |
| 从右往左 | ~ ++ -- + 一元运算 - 一元运算 ()强制类型转换 new |
| 从左往右 | * / % |
| 从左往右 | + - |
| 从左往右 | << >> >>> |
| 从左往右 | < <= > >= |
| 从左往右 | == != |
| 从左往右 | & |
| 从左往右 | ^ |
| 从左往右 | \| |
| 从左往右 | && |
| 从左往右 | \|\| |
| 从右往左 | ?: |
| 从右往左 | = += -= *= /= %= &= \|= ^= <<= >>= >>>= |
若不适用括号,就按照给出的运算符优先级次序进行计算。同一个级别的运算符按照从左到右的次序进行计算(除了表中给出的右结合运算符外)。
## 参考资料
[1] 《Java核心技术 卷I 基础知识》 ------【美】凯S. 霍斯特曼

287
Java/3. 控制流程.md Normal file
View File

@ -0,0 +1,287 @@
# 3. 控制流程
跟任何的程序设计语言一样Java使用条件语句和循环结构确定控制流程。
## 3.1 块作用域
**块**是指由一对大括号括起来的若干条简单的Java语句块确定了变量的作用域。一个块可以*嵌套*在另一个块中。
> 常见例子:
>
> ```java
> public static void main(String[] args)
> {
> int n;
> ...
> {
> int k;
> ...
> }
> }
> ```
但是不能在嵌套的两个块中声明同名的变量。
> ```java
> public static void main(String[] args)
> {
> int n;
> ...
> {
> int k;
> int n;//无法通过编译
> ...
> }
> }
> ```
## 3.2 条件语句
在JAVA中条件语句的格式`if (condition) statement` 在这里的条件必须用括号括起来。
> 例子:
>
> ```java
> if(yourSales >= target)
> {
> performance = "Satisfactory";
> bonus = 100;
> }
> ```
>
> 如果变量yourSales大于等于变量target时就执行语句块类的内容。
还有一种条件语句的格式:`if (condition) statement1 else statement2`。
> 例子:
>
> ```java
> if(yourSales >= target)
> {
> performance = "Satisfactory";
> bonus = 100;
> }else{
> performance = "Unsatisfactory";
> bonus = 0;
> }
> ```
>
> ![if-else语句](./img/if-else.png)
其中else部分是可选的else子句与最近邻的if构成一组通常都会使用一对花括号将这段代码变得更加清晰。
> ```java
> if(x <= 0){
> if(x ==0 ){
> sign = 0;
> }else{
> sign = -1;
> }
> }
> ```
>
> 当变量x小于等于0时执行第一层括号内的内容。当变量x等于0时候sign等于0否则sign等于-1。
if语句通常还会使用多个。
> ```java
> if(yourSale >= 2*target){
> performance = "Excellent";
> bonus = 1000;
> }else if(yourSale >= 1.5*target){
> performance = "Fine";
> bonus = 500;
> }else if(yourSale >= target){
> performance = "Satisfactory";
> bonus = 100;
> }else{
> System.out.println("You're fired");
> }
> ```
>
> - 如果变量yourSale大于等于2倍的变量targetperformance的值就为“Excellent”bonus的值就等于1000
>
> - 否则如果变量yourSale大于等于1.5倍的变量targetperformance的值就为“Fine”bonus的值就等于500
>
> - 否则如果变量yourSale大于等于变量targetperformance的值就为“Satisfactory”bonus的值就等于100
>
> - 若上述条件都不满足则输出“You're fired"。
## 3.3 循环
当条件为true时while循环执行一条语句或语句块。语法格式为`while (condition) statement`。若开始循环条件的值为false则while循环体一次也不执行。
> ```java
> while(balance < goal){
> balance += payment;
> years++;
> }
> System.out.println(years + "years.");
> ```
>
> ![while循环](./img/while.png)
如果希望循环体至少执行一次则应该将被检测条件放在最后。用do-while循环语句可以实现这一操作。语法格式为`do statement while (condition)`。
> 还是上面的例子:
>
> ```java
> do{
> balance += payment;
> years++;
> }while(balance < goal)
> ```
>
> ![do-while循环](./img/do-while.png)
## 3.4 确定循环
for循环语句是支持迭代的一种通用结构利用每次迭代之后更新的计数器或类似的变量来控制迭代次数。
> 例子将数字1~10输出到屏幕上
>
> ```java
> for (int i = 1; i <= 10; i++){
> System.out.println(i);
> }
> ```
>
> ![for循环](./img/for.png)
for语句的第一部分通常用于对计数器初始化第二部分给出每次新一轮循环执行前要检测的循环条件第三部分指示如何更新计数器。
当for语句的第一部分声明了一个变量后这个变量的作用域就为for循环的整个循环体不能在循环体外使用。
```java
for (int i = 1; i <= 10; i++){
....//i只能作用域这块作用域
}
```
如果想要在for循环体外使用循环计数器的最终值就要确保这个变量在循环体语句前被声明。
```java
int i;
for(i = 1;i <= 10;i++){
...
}
//i在for块作用域外也能用
```
还可以在各自独立的不同for循环中定义同名的变量
```java
for (int i = 1; i <= 10; i++){
...
}
for (int i = 11; i <= 20; i++){
...
}
```
for循环语句是while循环的一种简化形式。
```java
int i = 10;
while(i > 0){
System.out.println("..."+i);
i--;
}
//等同于
for(int i = 10; i>0; i--){
System.out.println("..."+i);
}
```
## 3.5 中断控制流程语句
break语句用于退出循环。
>```java
>while(years <= 100){
> balance += payment;
> if(balance >= goal) break;
> years++;
>}
>```
>
> 在循环开始时若years>100或在循环体中balance >= goal就退出循环。
continue语句中断正常的控制流程语句将控制转移到最内层循环的首部。
> ```java
> while(sum < goal){
> n = in.nextInt();
> if(n < 0) continue;
> sum += n;
> }
> ```
>
> 如果n<0则continue语句越过了当前循环体的剩余部分立刻跳到循环首部
如果将continue语句用于for循环中就可以跳到for循环的“更新”部分。
> ```java
> for(int i=1;i<=100;i++){
> n = in.nextInt();
> if(n<0) continue;
> sum += n;
> }
> ```
>
> 如果n<0则continue语句跳到count++语句
## 3.6 多重选择switch语句
在处理多个选项时使用if-else结构会显得有些笨拙在这里Java也有一个switch语句。
```java
switch(choice)
{
case 1:
...;
break;
case 2:
...;
break;
case 3:
...;
break;
case 4:
...;
break;
default:
...;
break;
}
```
switch语句将从与选项值相匹配的case标签处开始执行直到遇到break语句或执行到switch语句的结束处为止。若没有匹配的case标签有default子句的话就会执行这个子句。
注意若在case分支语句的末尾没有break语句那么就会接着执行下一个case分支语句这时候不看条件是否成立都会执行
## 参考资料
[1] 《Java核心技术 卷I 基础知识》 ------【美】凯S. 霍斯特曼

372
Java/4.数组.md Normal file
View File

@ -0,0 +1,372 @@
# 4.数组
如果我们需要存储大量的数据比如存储100名学生的成绩这就要重复声明100个变量再比如让100名学生的成绩全部加一也是100个变量重复操作这样太麻烦过于繁琐重复操作过多无法进行统一的操作。
## 4.1数组的概念
一组连续的存储空间,存储多个相同数据类型的值。同一种类型数据的集合。其实数组就是一个容器。运算的时候有很多数据参与运算,那么首先需要做的是什么.不是如何运算而是如何保存这些数据以便于后期的运算,那么数组就是一种用于存储数据的方式,能存数据的地方我们称之为容器,容器里装的东西就是数组的元素, 数组可以装任意类型的数据,虽然可以装任意类型的数据,但是定义好的数组只能装一种元素, 也就是数组一旦定义,那么里边存储的数据类型也就确定了。
特点类型相同长度固定可以自动给数组中的元素从0开始编号方便操作这些元素。
## 4.2 数组的定义
- 数组的创建:
> 元素类型[] 数组名 = new 元素类型[元素个数或数组长度];
- 声明数组变量
必须在程序中声明数组并指定数据类型声明数据类型为int容器使用数组那么如何标识数组呢在java中我们使用[]符号标识然后接着是定义数组的名称为arr格式为 int[] arr。注意int x[] 也是一种创建数组的格式。推荐使用int[] x 的形式声明数组。
- 创建数组
要使用一个新的关键字叫做newnew 用来在内存中产生一个容器实体数据要存储是需要有空间的存储很多数据的空间用new 操作符来开辟new int[5]; 这个5是元素的个数。右边这部分就是在内存中定义了一个真实存在的数组能存储5个元素。注意new int[5] 做了两件事情首先使用new int[3] 创建了一个数组然后把这个数组的引用赋值给数组变量x。
==思考:== arr是属于什么数据类型
任何一个变量都得有自己的数据类型。注意这个arr不是int 类型的 。int 代表的是容器里边元素的类型。那么x 是数组类型的数组是一种单独的数据类型。数据类型分为2大派分为基本数据类型和引用数据类型。 第二大派是引用数据类型。那么大家现在已经接触到了引用数据类型三种当中的一种。就是数组类型 [] 中括号就代表数组。
==思考:== int[] arr = new int[5];在内存中发生了什么?
内存任何一个程序,运行的时候都需要在内存中开辟空间.int[] arr = new int[5]; 这个程序在内存中是什么样?这就涉及到了java虚拟机在执行程序时所开辟的空间,那么Java开辟启动了多少空间呢在后面我们会深入介绍。
定义数组主要有两种格式:
格式一:
```java
元素类型[] 数组名 = new 元素类型[元素个数或数组长度];
示例int[] arr1 = new int[5];
示例float[] arr2 = new float[5];
```
格式二:
```java
元素类型[] 数组名 = new 元素类型[]{元素,元素,……};
int[] arr1 = new int[]{3,5,1,7};
float[] arr2 = {1.3,1.5,1.1,1.7};
```
==注意:== 给数组分配空间时必须指定数组能够存储的元素个数来确定数组大小体现了数组长度固定的特点创建数组之后不能修改数组的大小。可以使用length 属性获取数组的大小。
## 4.3 数组的初始化
- 数组的声明与赋值
```java
int[] arr = new int[2];
a[0] = 10;
a[1] = 20;
```
另一种方式也可以直接明确数组的长度,以及数组中元素的内容:
```java
int[] arr = new int[]{20,30,40};
int[] arr = {20,30,40};
```
如果数组初始化中不使用运算符new。需要注意下列写法是错误的
```java
int[] arr;
arr = {20,30,40};
```
初始化数组,必须将声明,创建,初始化都放在一条语句中个,分开会产生语法错误。
![在这里插入图片描述](img/20210401014138779.png)
## 4.4 数组下标的有效范围与常见异常
- ArrayIndexOutOfBoundsException 索引值越界异常。
我们进行了数组声明、赋值和访问之后,下面我们来讨论一下数组下标的有效范围。如下面一个例子中:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210401014244844.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NzU1MzAxNw==,size_16,color_FFFFFF,t_70)
我们发现长度为5的数组再给每一个有效的元素依次赋值再然后完成访问。但是在访问过程中arr[3]是较为特殊的那我们就要明确对于一个数组来见有效的下标范围是0 ~ 数组长度-1也就是说作为一个长度为三的数组来讲有效下标范围应该是0 ~ 2一旦我们访问了不在有效范围的下标那么就会产生数组下标越界异常。
> Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException:
> Index 3 out of bounds for length 3
- NullPointerException 空指针异常
引用类型变量没有指向任何对象,而访问了对象的属性或者是调用了对象的方法。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210401014448158.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NzU1MzAxNw==,size_16,color_FFFFFF,t_70)
## 4.5 数组内存分析
- 栈内存:栈内存存储的都是局部变量,变量一旦出了自己的作用域,那么就会马上从内存的消失,释放内存空间。
- 堆内存:堆内存存储的都是对象内存,对象一旦被使用完,并不会马上从内存中消失,而是等待垃圾回收器不定时的把垃圾对象回收,这时候该对象才会消失,释放内存。
- 凡是以new关键字创建的对象JVM都会在堆内存中开辟一个新的空间创建一个新的对象。
- 对象如果没有变量引用了,那么该对象就是一个垃圾对象了。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210401014539315.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NzU1MzAxNw==,size_16,color_FFFFFF,t_0)
**双数组的内存分析**
```java
public class Test2 {
public static void main(String[] args) {
int[] arr1 = new int[2];
int[] arr2 = new int[3];
System.out.println(arr1);
System.out.println(arr1[0]);
System.out.println(arr1[1]);
System.out.println(arr2);
System.out.println(arr2[0]);
System.out.println(arr2[1]);
System.out.println(arr2[2]);
// 给arr1数组的索引为0元素赋值100
arr1[0] = 100;
// 给arr2数组的索引为0元素赋值200
arr2[0] = 200;
System.out.println("-----------");
System.out.println(arr1);
System.out.println(arr1[0]);
System.out.println(arr1[1]);
System.out.println(arr2);
System.out.println(arr2[0]);
System.out.println(arr2[1]);
System.out.println(arr2[2]);
}
}
```
![在这里插入图片描述](https://img-blog.csdnimg.cn/2021040101463068.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NzU1MzAxNw==,size_16,color_FFFFFF,t_0)
## 4.6 二维数组
我们有个酒店500个房间并且所有房间都在同一个楼层里那么拿到499号房钥匙的旅客可能就不高兴了从1号房走到 499号房要花好长时间因此每个酒店都不只有一个楼层而是很多楼层每一个楼层都会有很多房间形成一个立体的结构把大量的房间均摊到每个楼层这种结构就是二维表结构。在计算机中二维表结构可以使用二维数组来表示。使用二维表结构表示快捷酒店每一个楼层的房间号的效果如下图所示。
### 4.6.1 创建二维数组
二维数组可以看作是特殊的一维数组,它有两种声明方式:
```java
数组元素类型 数组名字[][];
数组元素类型[][] 数组名字;
int arr1[][];
char[][] arr2;
```
同一维数组一样,二维数组在声明时也没有分配内存空间,同样要使用关键字**new**来分配内存,然后才可以访问每个元素。
为二维数组分配内存有两种方式∶
```java
int a[][];
a = new int[2][4]; //直接分配行类
int b[][];
b = new int[2][]; //先分配行,再分配列
b[0] = new int[2]; //给第一行分配列
b[1] = new int[2]; //给第二行分配列
```
==注意:== 创建二维数组的时候,可以只声明"行"的长度,而不声明"列"的长度,例如∶
```java
int a[][] = new int[][]; //可省略列的长度
```
但如果不声明"行"数量的话,就是错误的写法,例如∶
```java
// 错误写法!
int b[][] = new int[][];
// 错误写法!
int c[][] = new int[][2];
```
### 4.6.2 二维数组的赋值
二维数组的初始化方法与一维数组类似也有3种方式。但不同的是二维数组有两个索引即下标构成由行和列组成的一个矩阵。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210401015902387.png)
**使用三种方式初始化二维数组**
```java
public class InitTDArray {
public static void main(String[] args) {
/* 第一种方式 */
int tdarr1[][] = { { 1, 3, 5 }, { 5, 9, 10 } };
/* 第二种方式 */
int tdarr2[][] = new int[][] { { 65, 55, 12 }, { 92, 7, 22 } };
/* 第三种方式 */
int tdarr3[][] = new int[2][3]; // 先给数组分配内存空间
tdarr3[0] = new int[] { 6, 54, 71 }; // 给第一行分配一个一维数组
tdarr3[1][0] = 63; // 给第二行第一列赋值为63
tdarr3[1][1] = 10; // 给第二行第二列赋值为10
tdarr3[1][2] = 7; // 给第二行第三列赋值为7
}
}
```
从这个例子可以看出,二维数组每一个元素也是一个数组,所以第一种直接赋值方式,在大括号内还有大括号,因为每一个元素都是一个一维数组;第二种使用 new 的方法与一维数组类似; 第三种比较特殊,在分配内存空间之后,还有两种赋值的方式,给某一行直接赋值一个一维数组,或者给某一行的每一个元素分别赋值。开发者可以根据使用习惯和程序要求灵活地选用其中一种赋值方式。
### 4.6.3 多为数组
比一维数组维数高的叫多维数组理论上二维数组也属于多维数组。Java也支持三维、四维等多维数组创建其他多维数组的方法与创建二维数组类似。
```java
int a[][][] = new int[3][4][5];//创建三维数组

char b[][][][] = new char[6][7][8][9];//创建四维数纹

double c[][][][][]= new double[10][11][12][13][14]; // 建wu维数组
```
==注意:== 多维数组在Java中是可以使用的但因为其结构关系太过于复杂容易出错所以不推荐在程序中使用比二维数组更高维数的数组如果需要存储复杂的数据推荐使用集合类或自定义类集合类包括List、Map等这些集合类感兴趣的小伙伴可以了解一下。
### 4.6.4 通过二维数组输出不同版式的古诗
创建Poetry类声明一个字符型二维数组将古诗《春晓》的内容赋值于二维数组然后分别用横版和竖版两种方式输出实例代码如下
```java
public class Poetry {
public static void main(String[] args) {
char arr[][] = new char[4][]; // 创建一个4行的二维数组
arr[0] = new char[] { '春', '眠', '不', '觉', '晓' }; // 为每一行赋值
arr[1] = new char[] { '处', '处', '闻', '啼', '鸟' };
arr[2] = new char[] { '夜', '来', '风', '雨', '声' };
arr[3] = new char[] { '花', '落', '知', '多', '少' };
/* 横版输出 */
System.out.println("-----横版-----");
for (int i = 0; i < 4; i++) { // 循环4行
for (int j = 0; j < 5; j++) { // 循环5列
System.out.print(arr[i][j]); // 输出数组中的元素
}
if (i % 2 == 0) {
System.out.println(","); // 如果是一、三句,输出逗号
} else {
System.out.println("。"); // 如果是二、四句,输出句号
}
}
/* 竖版输出 */
System.out.println("\n-----竖版-----");
for (int j = 0; j < 5; j++) { // 列变行
for (int i = 3; i >= 0; i--) { // 行变列,反序输出
System.out.print(arr[i][j]); // 输出数组中的元素
}
System.out.println(); // 换行
}
System.out.println("。,。,"); // 输出最后的标点
}
}
```
输出结果如下:
![在这里插入图片描述](img/20210401020646668.png)
## 4.7 不规则数组
上文讲的数组都是行、列固定的矩形方阵, Java同时也支持不规则的数组例如二维数组中不同行的元素个数可以不同例如
```java
a[][] = new int[3][];// 创建二维数组,指定行数,不指定列数
a[0]= new int[5];// 第一行分配5个元素
a[1] = new int[3];// 第二行分配3个元素
a[2] = new int[4];// 第三行分配4个元素
```
这个不规则二维数组所占的空间如图所示。
![在这里插入图片描述](img/20210401020807311.png)
输出不规则二维数组中的所有元素
创建IrregularArrax类声明一个不规则二维数组输出数组每行的元素个数及各元素的值代码如下
```java
public class IrregularArray {
public static void main(String[] args) {
int a[][] = new int[3][]; // 创建二维数组,指定行数,不指定列数
a[0] = new int[] { 52, 64, 85, 12, 3, 64 }; // 第一行分配5个元素
a[1] = new int[] { 41, 99, 2 }; // 第二行分配3个元素
a[2] = new int[] { 285, 61, 278, 2 }; // 第三行分配4个元素
for (int i = 0; i < a.length; i++) {
System.out.print("a[" + i + "]中有" + a[i].length + "个元素,分别是:");
for (int tmp : a[i]) { // foreach循环输出数字中元素
System.out.print(tmp + " ");
}
System.out.println();
}
}
}
```
## 4.8 数组的基本操作
### 4.8.1 数组遍历
遍历数组就是获取数组中的每个元素。通常遍历数组都是使用for循环来实现。遍历一维数组很简单也很好理解下面详细介绍遍历二维数组的方法。
遍历二维数组需使用双层for循环通过数组的length属性可获得数组的长度。
创建Trap类定义二维数组实现将二维数组中的每一个元素按照行、列格式进行输出代码如下
```java
public class Trap {
public static void main(String[] args) {
int b[][] = new int[][] { { 1 }, { 2, 3 }, { 4, 5, 6 } }; // 定义二维数组
for (int k = 0; k < b.length; k++) { // 循环遍历二维数组中第一个索引
for (int c = 0; c < b[k].length; c++) { // 循环遍历二维数组中第二个索引
System.out.print(b[k][c]); // 将数组中的元素输出
}
System.out.println(); // 输出换行
}
}
}
```
本实例中有一个语法需要掌握∶ 如果有一个二维数组a[][]a.length返回的是数组的行数a[0]. length返回的是第一行的列数量a[1].length返回的是第二行的列数量。同理a[n]返回的是第n+1行的列数量由于二维数组可能是不规则数组所以每一行的列数量可能不相同因此在遍历二维数组时最好使用数组的length属性控制循环次数而不是用某他变量或常量。
**练一练:使用二维数组实现杨辉三角算法。**
```java
public class YangHui {// 杨辉三角算法的实现
public static void main(String[] args) {
// 定义一个长度为10的二维数组
int[][] Array_int = new int[10][];
// 向数组中记录杨辉三角形的值
for (int i = 0; i < Array_int.length; i++) {// 遍历行数
Array_int[i] = new int[i + 1];// 定义二维数组的列数
// 遍历二维数组的列数
for (int j = 0; j < Array_int[i].length; j++) {
if (i <= 1) {// 如果是数组的前两行
Array_int[i][j] = 1;// 将其设置为1
continue;
} else {
// 如果是行首或行尾
if (j == 0 | j == Array_int[i].length - 1)
Array_int[i][j] = 1;// 将其设置为1
else// 根据杨辉算法进行计算
Array_int[i][j] = Array_int[i - 1][j - 1] + Array_int[i - 1][j];
}
}
}
for (int i = 0; i < Array_int.length; i++) {// 输出杨辉三角
for (int j = 0; j < Array_int[i].length; j++)
System.out.print(Array_int[i][j] + "\t");
System.out.println();
}
}
}
```
运行结果如下:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210401091412192.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NzU1MzAxNw==,size_16,color_FFFFFF,t_70)
### 4.8.2 填充和替换数组元素
数组中的元素定义完成后可通过Arrays类的静态方法fill()方法来对数组中的元素进行分配起到填充和替换的效果。fill()方法可将指定的int值分配给int型数组的每个元素。语法如下
> Arrays.fill()(int[] a ,int value)
a要进行元素分配的数组。
value要存储数组中所有元素的值。
**使用 **fill()** 方法将空数组填满数值**
创建 Swap类通过fill()方法填充数组元素,最后将数组中的各个元素输出,代码如下∶
```java
import java.util.Arrays; //导入java.util.Arrays类
public class Swap {
public static void main(String[] args) {
int arr[] = new int[5]; // 创建int型数组
Arrays.fill(arr, 8); // 使用同一个值对数组进行填充
for (int i = 0; i < arr.length; i++) { // 循环遍历数组中的元素
// 将数组中的元素依次输出
System.out.println("第" + i + "个元素是:" + arr[i]);
}
}
}
```
# 总结
- 为什么数组的索引从0开始
为什么索引是从0开始的而不是从1开始呢这是继承了汇编语言的传统从0开始更利于计算机做二进制的运算和查找。
- 数组长度使用length属性获得但实际上这个属性只能表示一个一维数组的长度。二维数组使用length属性的方式其实是将二维数组转为"一维数组[一维数组下]"的形式即一维数组中的元素仍然是一个一维数组所以二维数组在遍历时使用的两个length并不是同一个数组的属性。
- 本章介绍的是数组的创建及使用方法。需要注意的是数组的下标是从0开始最后一个元素的下标总是"**数组名 .length-1**"。本章的重点是创建数组、给数组赋值以及读取数组中元素的值。此外Arrays类还提供了其他操作数组的方法有兴趣的读者可以查阅相关资料。

361
Java/5.类与方法.md Normal file
View File

@ -0,0 +1,361 @@
# 5. 类与方法
## 5.1 面向对象概述
- 面向机器语言
计算机处理信息的早期语言是所谓的机器语言使用机器语言进行程序设计需要面向机器来编写代码即需要针对不同的机器编写诸如0101 1100这样的指令序列。
- 面向过程语言
随着计算机硬件功能的提高,在20世纪60年代出现了面向过程设计语言如C语言等。用这些语言编程也称为面向过程编程。语言把代码组成叫做过程或函数的块。每个块的目标是完成某个任务。使用这些语言编写代码指令时不必再去考虑机器指令的细节只要按着具体语言的语法要求去编写“源文件”。
- 面向对象语言
基于对象的编程更加符合人的思维模式,使得编程人员更容易编写出易维护、易扩展和易复用的程序代码,更重要的是,面向对象编程鼓励创造性的程序设计。
**面向对象编程主要体现下列三个特性:封装性 ;继承;多态**
## 5.2 类与对象
- Java语言是面向对象语言它的源程序是由若干个类组成源文件是扩展名为 **.java** 的文本文件。
- 类是Java语言中最重要的“数据类型”类声明的变量被称作对象即类是用来创建对象的模板。
- 类的实现包括两部分:类声明和类体。基本格式为:
```java
class 类名 {
//类的成员变量
//类的成员方法
//类体的内容等
}
```
其中:**class**是关键字,用来**定义类**。“class 类名”是类的声明部分类名必须是合法的Java标识符。两个大括号以及之间的内容是类体。
### 5.2.1 成员变量
在 Java 中对象的属性也称为成员变量,成员变量的定义与普通变量的定义一样,语法如下:
> 数据类型 变量名称[=值]
其中,[=值]表示可选内容定义变量时可以为其赋值也可以不为其赋值。为了了解成员变量首先定义一个鸟类——Bird类成员变量对应于类对象的属性在Bird类中设置4个成员变量分别为wing、claw、beak和feather分别对应于鸟类的翅膀、爪子、喙和羽毛。
例如在项目中创建鸟类Bird在该类中定义成员变量。代码如下
```java
public class Bird{
String wing; //翅膀
String claw; //爪子
String beal; //喙
String feather; //羽毛
}
```
从以上代码可以看到在Java中使用class 关键字来定义类Bird是类的名称。同时在Bird类中定义了4个成员变量成员变量的类型可以设置为Java中合法的数据类型其实成员变量就是普通的变量可以设置初始值也可以不设置初始值。如果不设置初始值则会有默认值。
![在这里插入图片描述](img/20210331182138470.png)
![在这里插入图片描述](img/2021033118215646.png)
### 5.2.2 成员方法
1. 成员方法的定义定义成员方法的语法格式如下:
```java
[权限修饰符] [返回值类型]方法名([参数类型 参数名])[throws 异常类型]{
//方法体
return 返回值;
}
```
其中,权限修饰符可以是 private、publicprotected中的任意一个也可以不写主要用来控制方法的访问权限。返回值类型用来指定方法返回数据的类型可以是任何类型如果方法不需要返回值则使用void关键字一个成员方法既可以有参数也可以没有参数参数可以是对象也可以是基本数据类型的变量。
例如,定义一个 showGoods()方法,用来输出库存商品信息,代码如下∶
```java
public void showGoods(){
System.out.println("库存商品信息:");
}
```
说明∶方法的定义必须在某个类中,定义方法时如果没有指定权限修饰符,方法的默认访问权限为缺省(即只能在本类及同一个包中的类中进行访问)。
如果定义的方法有返回值则必须使用return关键字返回一个指定类型的数据并且返回值类型要与方法返回值的类型一致。例如定义一个返回值类型为int的方法就必须使用return返回一个int类型的值代码如下
```java
public int showGoods(){
System.out.println("库存商品信息:");
returun 1;
}
```
上面代码中,如果将 **return 1;** 删除,将会出现错误提示。
2. 成员方法的参数
调用方法时可以给该方法传递一个或多个值传给方法的值叫作实参在方法内部接收实参的变量叫作形参形参的声明语法与变量的声明语法一样。形参息在方法内部有效。Java中方法的参数主要有3 种,分别为值参数、引用参数和不定长参数,下面分别进行讲解。
- **值参数**
值参数表明实参与形参之间按值传递,当使用值参数的方法被调用时,编译器为形参分配存储单元,然后将对应的实参的值复制到形参中,由于是值类型的传递方式,所以,在方法中对值类型的形参的修改并不会影响实参。
**实例1计算箱子里图书的总数**
书架上有30本书箱子里有40本书把书架上的书全部放进箱子后使用带参数的成员方法计算箱子里书的总数。代码如下
```java
public class Book { // 创建书类
public static void main(String[] args) {
Book book = new Book(); // 创建书类对象
int shelf = 30; // 初始化书架上书的本数(实参)
int box = 40; // 初始化箱子里书的本数(实参)
// 把书架上的书全部放进箱子后,输出箱子里书的总数
System.out.println("把书架上的书全部放进箱子后,箱子里一共有"
+ book.add(shelf, box) + "本书。\n明细如下书架上"
+ shelf + "本书,箱子里原有" + box + "本书。");
}
private int add(int shelf, int box) { // 把书架上、箱子里的书相加求和(形参)
box = box + shelf; // 对box进行加shelf操作
return box; // 返回box
}
}
```
运行结果如下图所示:
![在这里插入图片描述](img/20210331183921787.png)
我们从结果可以看出在成员方法中修改形参box值之后并没有改变实参box的值。
- **引用参数**
如果在给方法传递参数时,参数的类型是数组或者其他引用类型,那么,在方法中对参数的修改会反映到原有的数组或者其他引用类型上,这种类型的方法参数被称之为引用参数。
实例2将美元转换为人民币
现有1美元、10美元和100美元三种面值的美钞将这三种面值的美钞存储在double类型的数组中如果当前1美元可兑换6.903元人民币那么使用参数为double类型的数组的成员方法将三种面值的美钞转换为等值的人民币。代码如不
```java
public class ExchangeRate { // 创建汇率类
public static void main(String[] args) {
ExchangeRate rate = new ExchangeRate(); // 创建RefTest对象
double[] denomination = { 1, 10, 100 }; // 定义一维数组,用来存储纸币面额(实参)
// 输出数组中三种面值的美钞
System.out.print("美元:");
for (int i = 0; i < denomination.length; i++) { // 使用for循环遍历数组
System.out.print(denomination[i] + "美元 ");
}
rate.change(denomination); // 调用方法改变数组中元素的值
// 输出与三种面值的美钞等值的人民币
System.out.print("\n人民币");
for (int j = 0; j < denomination.length; j++) { // 使用for循环遍历数组
System.out.print(denomination[j] + "元 ");
}
}
// 定义一个方法,方法的参数为一维数组(形参)
public void change(double[] i) {
for (int j = 0; j < i.length; j++) { // 使用for循环遍历数组
i[j] = i[j] * 6.903; // 将数组中的元素乘以当前汇率
}
}
}
```
- **不定长参数**
声明方法时,如果有若干个相同类型的参数,可以定义为不定长参数,该类型的参数声明如下∶
权限修饰符 返回值类型 方法名(参数类型... 参数名)
==注意∶== 参数类型和参数名之间是三个点,而不是其他数量或省略号。
### 5.2.3 构造方法
在类中除了成员方法之外,还存在一种特殊类型的方法,那就是构造方法。构造方法是一个与类同名的方法,对象的创建就是通过构造方法完成的。每当类实例化一个对象时,类都会自动调用构造方法。
构造方法的特点如下∶
- 构造方法没有返回类型也不能定义为void。
- 构造方法的名称要与本类的名称相同。
- 构造方法的主要作用是完成对象的初始化工作,它能把定义对象的参数传给对象成员。
==注意:== 在定义构造方法时构造方法没有返回值但这与普通没有返回值的方法不同普通没有返回值的方法使用public void Text()这种形式进行定义但构造方法并不需要使用void关键字进行修饰。
构造方法的定义语句代码如下:
```java
class Book{
public Book(){ //(无参)构造方法
}
}
```
- ==public== 构造方法的修饰符
- ==Book== 构造方法的名称
在构造方法中可以为成员变量赋值,这样当实例化一个本类的对象时,相应的成员变量也将被初始化。如果类中没有明确定义构造方法,则编译器会自动创建一个不带参数的默认构造方法。

除此之外,在类中定义构造方法时,还可以为其添加一个或者多个参数,即有参构造方法,语法如下:
```java
class Book {
public Book(int args){ //有参构造方法
//对成员变量进行初始化
}
}
```
==注意:== 如果在类中定义的构造方法都是有参构造方法,则编译器不会为类自动生成一个默认的无参构造方法,当试图调用无参构造方法实例化一个对象时,编译器会报错。所以只有在类中没有定义任何构造方法时,编译器才会在该类中自动创建一个不带参数的构造方法。
**实例3 借阅《战争与和平》**
创建一个借书类 BorrowABook借书类中有默认构造方法和参数为书名的借书方法 borrow()。编写一个程序,使用默认构造方法借阅《战争与和平》这本书。代码如下∶
```java
public class BorrowABook { // 创建借书类
public BorrowABook() { // 无参构造方法
}
public void borrow(String name) { // 参数为书名的借书方法
System.out.println("请前往借阅登记处领取" + name + "。"); // 输出借出的书名
}
public static void main(String[] args) {
BorrowABook book = new BorrowABook(); // 创建借书类对象,
book.borrow("《战争与和平》"); // 调用借书方法并将“《战争与和平》”赋给参数name
}
}
```
### 5.2.4 this关键字
当类中的成员变量与成员方法中的参数重名时,方法中如何使用成员变量呢?首先来看一下重名的情况下会发生什么问题。
例如创建Book2类定义一个成员变量name并赋初值再定义一个成员方法showName(String name)输出方法中name的值。
![在这里插入图片描述](img/20210401010138710.png)
从这个结果可以看出,输出的值不是成员变量的值,也就是说,如果方法中出现了与局部变量同名的参数,会导致方法无法直接使用成员变量。

在上述代码中可以看到,成员变量与在 showtName()方法中的形式参数的名称相同都为name那么如何在类中区分使用的是哪一个变量呢在Java语言中规定使用this关键字来代表本类对象的引用this关键字被隐式地用于引用对象的成员变量和方法。
**实例4 调用书名属性**
创建一个借书类 BorowABook借书类中有书名属性 name参数为 name 的构造方法和借书方法 borrow()。编写一个程序使用this关键字调用书名属性后借阅《战争与和平》这本书。代码如下
```java
public class BorrowABook2 { // 创建借书类
String name; // 属性:书名
public BorrowABook2(String name) { // 参数为name的构造方法
this.name = name; // 将参数name的值付给属性name
}
public void borrow() { // 借书方法
System.out.println("请前往借阅登记处领取" + name + "。"); // 输出借出的书名
}
public static void main(String[] args) {
// 创建参数为“《战争与和平》”的借书类对象,
BorrowABook2 book = new BorrowABook2("《战争与和平》");
book.borrow(); // 调用借书方法
}
}
```
- this关键字虽然可以调用成员变量和成员方法但Java语言中最常规的调用方式是使用"**对象.成员变量**"或"**对象.成员方法**"进行调用(关于使用对象调用成员变量和方法的问题,将在后续学习中进行讲述)。
- 
既然 this关键字和对象都可以调用成员变量和成员方法那么this关键字与对象之间具有怎样的关系呢?
- 事实上this关键字引用的就是本类的一个对象在局部变量或方法参数覆盖了成员变量时如上面代码的情况就要添加this关键字明确引用的是类成员还是局部变量或方法参数。
- 如果省略this关键字直接写成name = name那只是把参数name赋值给参数变量本身而已成员变量name的值没有改变因为参数name在方法的作用域中覆盖了成员变量name。
- 其实this关键字除了可以调用成员变量或成员方法之外还可以作为方法的返回值。例如在项目中创建一个类文件在该类中定义Book类型的方法并通过过this关键字进行返回。
```java
public class Book{
public getBook(){
return this; //返回Book类引用
}
}
```
在 getBook()方法中,方法的返回值为*Book*类,所以方法体中使用*return this* 这种形式将Book类的对象进行返回。通过介绍知道this关键字可以调用类的成员变量和成员方法。此外它还可以调用类中的构造方法。
### 5.2.5 static 关键字
由static修饰的变量、常量和方法分别被称作静态变量、静态常量和静态方法也被称作类的静态成员。
### 5.2.6 静态变量
很多时候不同的类之间需要对同一个变量进行操作比如一个水池同时打开入水口和出水口进水和出水这两个动作会同时影响到水池中的水量此时水池中的水量就可以认为是一个共享的变量。在Java程序中如果把共享的变量用static修饰那么该变量就是静态变量。调用静态变量的语法如下
> 类名.静态类成员
### 5.2.7 静态方法
如果想要使用类中的成员方法,需要先将这个类进行实例化,但有些时候不想或者无法创建类的对象时,还要调用类中的方法才能够完成业务逻辑,这种情况下就可以使用静态方法。
调用类的静态方法语法如下∶
> 类名.静态方法();
**实例6 使用静态方法表示水池中的水量及其变化**
创建一个水池类使用静态变量表示水池中的水量并初始化水池中的水量为0通过注水方法一次注入3个单位和放水方法一次放出2个单位控制水池中的水量。代码如下
```java
public class Pool { // 创建水池类
public static int water = 0; // 初始化静态变量之水池中的水量为0
public static void outlet() { // 放水一次放出2个单位
if (water >= 2) { // 如果水池中的水量大于等于2个单位
water = water - 2; // 放出2个单位的水
} else { // 如果水池中的水量小于2个单位
water = 0; // 水池中的水量为0
}
}
public static void inlet() { // 注水一次注入3个单位
water = water + 3; // 注入3个单位的水
}
public static void main(String[] args) {
System.out.println("水池的水量:" + Pool.water); // 输出水池当前水量
System.out.println("水池注水两次。");
Pool2.inlet(); // 调用静态的注水方法
Pool2.inlet(); // 调用静态的注水方法
System.out.println("水池的水量:" + Pool.water); // 输出水池当前水量
System.out.println("水池放水一次。");
Pool2.outlet(); // 调用静态的放水方法
System.out.println("水池的水量:" + Pool.water); // 输出水池当前水量
}
}
```
### 5.2.8 静态代码块
在类的成员方法之外用static修饰代码区域可以称之为静态代码块。定义一块静态代码块可以完成类的初始化操作在类声明时就会运行。语法如下
```java
public class StaticTest {
static {// 此处编辑执行语句
}
}
```
**实例7 代码块的执行顺序**
创建静态代码块、非静态代码块、构造方法、成员方法,查看这几处代码的调用顺序。代码如下:
```java
public class StaticTest {
static String name;
// 静态代码块
static {
System.out.println(name + "静态代码块");
}
// 非静态代码块
{
System.out.println(name + "非静态代码块");
}
public StaticTest(String a) {
name = a;
System.out.println(name + "构造方法");
}
public void method() {
System.out.println(name + "成员方法");
}
public static void main(String[] args) {
StaticTest s1;// 声明的时候就已经运行静态代码块了
StaticTest s2 = new StaticTest("s2");// new的时候才会运行构造方法
StaticTest s3 = new StaticTest("s3");
s3.method();// 只有调用的时候才会运行
}
}
```
### 5.2.9 类的主方法
主方法是类的入口点它指定了程序从何处开始提供对程序流向的控制。Java编译器通过主方法来执行程序。
主方法的语法如下∶
```java
public static void main(String[] args){
// 方法体
}
```
在主方法的定义中可以看到主方法具有以下特性∶
- 主方法是静态的,所以如要直接在主方法中调用其他方法,则该方法必须也是静态的。
- 主方法没有返回值。
- 主方法的形参为数组。其中 *args[0]args[n]* 分别代表程序的第一个参数到第n+1个参数可以使用 *args.length* 获取参数的个数。
# 三、小结
万事万物皆对象,数据也一样。任何数据都有一些独特的特性,可以将这些特性设置成类的属性。例如,时间包含年、月、日、时、分、秒,通信信息包括电话号和姓名等。数据可以被拆分,拆分出的特征就是类的属性。
本章学习了面向对象的概念、类的定义、成员方法、类的构造方法、主方法以及对象的应用等。通过对本章的学习读者应该掌握面向对象的编程思想这对Java的学习十分有帮助同时在此基础上读者可以编写类、定义类成员、构造方法、主方法以解决一些实际问题。由于在Java中通过对象来处理问题所以对象的创建、比较、销毁的应用就显得非常重要。初学者应该反复揣摩这些基本概念和面向对象的编程思想为Java语言的学习打下坚实的基础。

239
Java/6.继承与多态.md Normal file
View File

@ -0,0 +1,239 @@
# 6. 继承与多态
## 6.1 什么是继承
继承是面向对象编程中的特征之一,即从已有的类中派生出新的类,新的类具有父类的方法,同时也可以增加新的方法。这种特性使得复用代码非常容易,缩短开发周期。
例如兔子和羊属于食草动物类,狮子和豹属于食肉动物类。食草动物和食肉动物都属于动物类。
在java中使用extends 关键字来声明子类继承于某父类,如下:
```java
class 父类 {
}
class 子类 extends 父类 {
}
```
下面用一个例子说明继承
**公共父类**
```java
public class Animal {
private String name;
private int id;
public Animal(String myName) {
name = myName;
}
public void eat(){
System.out.println(name+"正在吃");
}
public void sleep(){
System.out.println(name+"正在睡");
}
public void introduction() {
System.out.println("我是" + name + ".");
}
}
```
**老虎类**
```java
public class tiger extends Animal {
public Penguin(String myName) {
super(myName);
}
}
```
**兔子类**
```java
public class rabbit extends Animal {
public Mouse(String myName) {
super(myName);
}
}
```
## 6.2 继承类型
继承又分单继承和多重继承Java不支持多继承。
单继承和多重继承。单继承是指一个子类最多只能有一个父类。多继承是一个子类可以有二个以上的父类。
多重继承例子如下:
```java
public class A{}
public class B extends A{}
public class C extends B{}
```
## 6.3 继承关键字
### 6.3.1 implements
Java除了extends还可以用implements关键字来实现继承。Java中不支持多重继承但是用implements可以实现多个接口相当于使得Java具有多继承的特性。
```java
public interface if1 {
public void method1();
}
public interface if2 {
public void method2();
}
public class if3 implements if1,if2 {
}
```
### 6.3.2 super与this
super引用当前对象的父类成员
this指向当前类的引用。
```java
class Father {
void method() {
System.out.println("这是父类的方法");
}
}
class Son extends Father {
void method() {
System.out.println("这是子类的方法");
}
void diff_method() {
this.method();
super.method();
}
}
public class Test {
public static void main(String[] args) {
Father father = new Father();
father.method();
Son son = new Son();
son.diff_method();
}
}
```
### 6.3.3 final
final即最终的不可变的。
final的功能是将类定义为不可继承的也可以用于修饰方法被修饰的方法不可被子类重写。
## 6.4 继承的特性
1. 子类不继承父类的private属性和方法
2. 子类可以对父类进行扩展,拥有自己的属性和方法
3. 子类是不继承父类的构造器构造方法或者构造函数它只是调用隐式或显式。如果父类的构造器带有参数则必须在子类的构造器中显式地通过super关键字调用父类的构造器并配以适当的参数列表
4. 如果父类构造器没有参数,则在子类的构造器中不需要使用 super 关键字调用父类构造器,系统会自动调用父类的无参构造器。
## 6.5 什么是多态
多态是同一个行为具有多个不同表现形式或形态的能力。例如一个人,可以是同时是数学家和物理学家。
## 6.6 多态的转型
多态的转型有向上转型和向下转型两种。
**向上转型**
当不需要面对子类类型时,通过提高扩展性,或者使用父类的功能就能完成相应的操作。
父类类型 变量名=new 子类类型()
**向下转型**
当要使用子类特有功能时。
子类类型 变量名=(子类类型) 父类类型的变量;
示例代码:
```java
public class Test {
public static void main(String[] args) {
show(new Cat()); // 以 Cat 对象调用 show 方法
show(new Dog()); // 以 Dog 对象调用 show 方法
Animal a = new Cat(); // 向上转型
a.eat(); // 调用的是 Cat 的 eat
Cat c = (Cat)a; // 向下转型
c.work(); // 调用的是 Cat 的 work
}
public static void show(Animal a) {
a.eat();
// 类型判断
if (a instanceof Cat) { // 猫做的事情
Cat c = (Cat)a;
c.work();
} else if (a instanceof Dog) { // 狗做的事情
Dog c = (Dog)a;
c.work();
}
}
}
abstract class Animal {
abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
public void work() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void work() {
System.out.println("看家");
}
}
```

View File

@ -0,0 +1,132 @@
# 7. 抽象类与接口
## 7.1 什么是抽象类
> 抽象类是它的所有子类的公共属性的集合,是包含一个或多个抽象方法的类。抽象类可以看作是对类的进一步抽象。首先从现实世界中的对象可以抽象出软件系统中的对象(保留主要属性和行为,去掉次要属性和行为),然后从软件系统中的对象可以抽象出软件系统中的类(去掉属性值,把具体的对象变成了抽象的概念),而抽象类则是对多个类的抽象结果,抽象类进一步描述了多个具体类的共同特征和行为。从系统分析的角度,使用抽象类可以更好地刻画自然界的抽象概念,更有效地完成软件系统与自然行为系统的映射,从系统设计实现的角度,使用抽象类可以更好地利用这些共同属性和操作,避免代码的重复编写,从而减少出错的几率,提高程序的开发效率。
抽象类简单理解,就是这个对象是什么。人和狗的抽象类都是动物。抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。
由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。也是因为这个原因,通常在设计阶段决定要不要设计抽象类。
Java是通过关键字abstract来实现抽象类的
```java
Modifies abstract class ClassName {…}
```
这里需要注意的是抽象类的修饰符必须为public或者protected不能是private因为创建抽象类就是要被其他类继承用private修饰了则不能被子类继承子类便无法实现该方法。
## 7.2 抽象方法
如果是实现一种方法,其具体内容由子类决定,就是抽象方法了。抽象方法只有声明,没有具体的实现:
```java
abstract void method();
```
- 如果一个类包含抽象方法,那么该类必须是抽象类。
- 任何子类必须重写父类的抽象方法,或者声明自身为抽象类。
## 7.3 继承抽象类
```java
abstract class A{
public void method(){
System.out.println("非抽象方法");
}
public abstract void abstract_method();
}
class B extends A{
@Override
public void abstract_method() {
System.out.println("新方法");
}
}
public class TestDemo {
public static void main(String[] args) {
A a = new B();
a.abstract_method();
}
}
```
## 7.4 什么是接口
接口在Java中书以抽象类型是抽象方法的集合。接口是比抽象类更抽象的存在Java接口的方法都没有实现并且都必须是抽象的。
从抽象层次上理解,抽象类是对类的抽象,接口是对行为的抽象。
接口中的所有属性默认为:**public static final**
接口中的所有方法默认为:**public abstract**
下面通过一个例子来看以下接口到底是什么
## 7.5 接口的实现
接口的继承关键字是 implements
```java
public interface Eat {
public void willEat();
}
public interface WatchDoor {
public void willWatchDoor();
}
public interface Think {
public void willThink();
}
public class Dog implements Eat,WatchDoor{
@Override
public void willEat() {
System.out.println("我会吃");
}
@Override
public void willWatchDoor() {
System.out.println("我会看家");
}
}
public class Person implements Eat,Think{
@Override
public void willEat() {
System.out.println("我会吃");
}
@Override
public void willThink() {
System.out.println("我会思考");
}
}
```
从示例代码应该可以看出,接口的主要功能是对于行为的继承。

155
Java/8. 异常处理.md Normal file
View File

@ -0,0 +1,155 @@
# 8. 异常处理
## 什么是异常?
异常是程序中的一些错误使得程序没有按照预期正常执行。Java提供了异常处理机制处理异常问题。
异常处理机制可以让程序在发生异常时,按照预先设计的逻辑处理异常。
产生异常的原因有很多,通常是:
- 用户输入了非法数据。
- 要打开的文件不存在。
- 网络通信时连接中断或者JVM内存溢出。
异常的类型有以下三种:
- **检查性异常:**最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
- **运行时异常:** 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
- **错误:** 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。
## 异常的分类
异常处理的根接口是Throwable有两个子接口分别是Error和Exception。
Error用来指示运行时环境发生的错误这是系统错误类一般开发人员无法处理只能关闭程序。
Exception指的是程序运行中产生的异常。
![img](img/exception-hierarchy.png)
Exception下的异常分为两大类分别是Runtime异常和非Runtime异常
Runtime异常程序运行时产生的异常jvm会自动处理。典型的运行时异常有数组下标越界异常IndexOutOfBoundsException、空指针异常NullPointerException、对象类型强制转换异常ClassCastException以及数组存储异常ArrayStoreException即数组存储类型不一致等。
非Runtime异常也叫检查异常即编译器要求必须进行处理的异常例如IOException、SqlException。
## 异常处理流程
Java异常机制用到的几个关键字try、catch、finally、throw、throws。
**try**: 用于监听。将要被监听的代码(可能抛出异常的代码)放在try语句块之内当try语句块内发生异常时异常就被抛出。
**catch**用于捕获异常。catch用来捕获try语句块中发生的异常。
**finally**finally语句块总是会被执行。它主要用于回收在try块里打开的物力资源(如数据库连接、网络连接和磁盘文件)。只有finally块执行完成之后才会回来执行try或者catch块中的return或者throw语句如果finally中使用了return或者throw等终止方法的语句则就不会跳回执行直接停止。
**throw**:用于抛出异常。
**throws**用在方法签名中用于声明该方法可能抛出的异常。主方法上也可以使用throws抛出。如果在主方法上使用了throws抛出就表示在主方法里面可以不用强制性进行异常处理如果出现了异常就交给JVM进行默认处理则此时会导致程序中断执行。
产生异常的原因:
## try-catch
```java
try
{
// 程序代码
}catch(ExceptionName e1)
{
//Catch 块
}
```
## try-catch-finally
finally 关键字用来创建在 try 代码块后面执行的代码块。
无论是否发生异常finally 代码块中的代码总会被执行。
在 finally 代码块中,可以运行清理类型等收尾善后性质的语句。
finally 代码块出现在 catch 代码块最后,语法如下:
```java
try{
// 程序代码
}catch(异常类型1 异常的变量名1){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}finally{
// 程序代码
}
```
## throws/throw
如果一个方法没有捕获到一个检查性异常,那么该方法必须使用 throws 关键字来声明。throws 关键字放在方法签名的尾部。
也可以使用 throw 关键字抛出一个异常,无论它是新实例化的还是刚捕获到的。
下面方法的声明抛出一个 RemoteException 异常:
```java
import java.io.*;
public class className {
public void deposit(double amount) throws RemoteException
{ // Method implementation throw new RemoteException(); } //Remainder of class definition }
```
一个方法可以声明抛出多个异常,多个异常之间用逗号隔开。
例如,下面的方法声明抛出 RemoteException 和 InsufficientFundsException
```java
import java.io.*;
public class className { public void withdraw(double amount) throws RemoteException, InsufficientFundsException { // Method implementation } //Remainder of class definition }
```
## 自定义异常
在 Java 中你可以自定义异常。编写自己的异常类时需要记住下面的几点。
- 所有异常都必须是 Throwable 的子类。
- 如果希望写一个检查性异常类,则需要继承 Exception 类。
- 如果你想写一个运行时异常类,那么需要继承 RuntimeException 类。
可以像下面这样定义自己的异常类:
class MyException extends Exception{ }
只继承Exception 类来创建的异常类是检查性异常类。
```java
class WrongInputException extends Exception { // 自定义的类
WrongInputException(String s) {
super(s);
}
}
class Input {
void method() throws WrongInputException {
throw new WrongInputException("Wrong input"); // 抛出自定义的类
}
}
class TestInput {
public static void main(String[] args){
try {
new Input().method();
}
catch(WrongInputException wie) {
System.out.println(wie.getMessage());
}
}
}
```

128
Java/9.反射.md Normal file
View File

@ -0,0 +1,128 @@
# 反射
## 反射概述
JAVA反射是在运行状态中对于任意一个类都能够知道这个类的所有属性和方法对于任意一个对象都能够调用它的任意方法和属性这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
**反射的功能**
1. 在运行时获取任意一个对象所属的类型信息,包括修饰符、泛型、父类、实现的接口、注解等;
2. 在运行时构造任意一个类的对象;
3. 在运行时获取任意一个类所具有的构造方法、成员变量和方法;
4. 在运行时访问任意一个对象的成员变量和方法;
**反射的应用**
1. 通过使用类全名创建类实例来使用外部用户定义的类。
> 例如Java数据库开发中需要在运行时使用JDBC驱动包中的驱动类可以通过反射机制在运行中获取。
> Class.forName( "com.mysql.cj.jdbc.Driver" );
2. 开发类浏览器和智能IDE。
> 例如Eclipse工具左侧的包浏览器可以查看类的结构右侧代码编辑区如果启用了提示功能在对象后输入“.”运算符会自动提示该对象所属类的所有可用属性和方法。这些IDE工具的功能需要反射机制实现。
3. 在测试工具中用于检测类的内部结构。
> 例如Java的单元测试框架Junit就是基于反射和注解实现的
4. 在框架开发中用于实现配置信息的处理。
> 例如Java Web开发中要学习的Struts2Spring的框架功能的实现都需要用到反射
5. 实现Java的动态代理。
**使用反射的注意事项**
反射是强大的,但不应滥用。如果可以在不使用反射的情况下进行操作,则优选避免使用反射。
反射增加了JVM的系统开销性能上比不使用反射慢。
反射可能违反某些安全策略。
反射允许访问私有成员,打破了封装,可能破坏可移植性。
## Class类
java.lang.Class类是所有Reflection API的切入点是所有反射操作的入口。
在Java程序运行过程中对程序中每种类型的对象Java虚拟机都会实例化一个不可变的java.lang.Class实例每个对象都是引用或者原始类型。
引用类型都继承自java.lang.Object。 类,枚举,数组和接口都是引用类型。
原始类型包括booleanbyteshortintlongcharfloat和double
**1.获取Class实例的三种方法最常用的是第3种**
对象.getClass()
类型名.class
Class.forName()
**2.用Class实例创建对象**
```java
//2.1通过newInstence(),此方式只适用于无参构造
Phone instance1 = (Phone) clazz1.newInstance();
//2.2先调用构造器再通过newInstence()创建
Constructor<?>[] cons = clazz1.getConstructor();
//假设第一个为无参构造
Phone instance2 = cons[0].newInstance();
//假设第二个构造方法为两个String类型参数
Phone instance3= cons[1].newInstance("s1","s2");
```
**3.获取指定属性Field和所有的属性Field**
获取成员变量的类型信息(了解)。
```
Class<?> c = Class.forName(className);
Field field = c.getField(fieldName);
Class typeClass = field.getType();
Type type = field.getGenericType();
```
**4.用反射的方式给对象的属性设置值,获取对象的属性值**
获取指定的方法Method和所有的方法Method
用反射的方式调用方法,获取调用的方法的返回值
获取指定的构造方法Constructor和所有构造方法Constructor
**通过Constructor实例创建对象。**
创建类实例(类对象)(重点掌握):
常规情况下是使用new操作符调用类的构造方法来创建类实例
```
Date date = new Date
```
使用反射创建类实例有两种方法:
```
Class.newInstance()
Constructor.newInstance(Object... initargs)
```
Class.newInstance()
只能调用类的无参数的非私有构造方法
抛出构造方法的异常
Constructor.newInstance(Object... initargs)
可以调用类的任何构造方法
用InvocationTargetException封装异常来抛出

View File

@ -0,0 +1,78 @@
package test;
import static java.lang.System.out;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
public class RefEx {
public static void main(String[] args) {
// TODO Auto-generated method stub
String s="hello";
Class c=s.getClass();//获取类型
System.out.println(c);
String modifiers=Modifier.toString(c.getModifiers());//获取修饰符
System.out.println(modifiers);
TypeVariable<?>[] tv = c.getTypeParameters();//获取泛型类型参数
if (tv.length != 0) {
out.format(" ");
for (TypeVariable<?> t : tv)
out.format("%s ", t.getName());
out.format("%n%n");
} else {
out.format(" -- No Type Parameters --%n%n");
}
Class superclass=c.getSuperclass();//获取类型的父类
System.out.println(superclass);
Type[] intfs = c.getGenericInterfaces();//获取类实现的接口
if (intfs.length != 0) {
for (Type intf : intfs)
out.format(" %s%n", intf.toString());
out.format("%n");
} else {
out.format(" -- No Implemented Interfaces --%n%n");
}
Annotation[] ann = c.getAnnotations();//获取类的注解
if (ann.length != 0) {
for (Annotation a : ann)
out.format(" %s%n", a.toString());
out.format("%n");
} else {
out.format(" -- No Annotations --%n%n");
}
Constructor[] cons=c.getDeclaredConstructors();//获取类的构造方法
for(Constructor con:cons){
System.out.println(con.toGenericString());
}
out.format("%n%n");
Field[] fs=c.getDeclaredFields();//获取类的数据成员成员变量
for(Field f:fs){
System.out.println(f.toGenericString());
}
out.format("%n%n");
Method[] ms=c.getMethods();//获取类的公有成员方法包含从父类继承的
for(Method m:ms){
System.out.println(m.toGenericString());
}
out.format("%n%n");
}
}

View File

@ -0,0 +1,87 @@
package test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test {
public static String classname="类.Student";
public static String fieldname="name";
public static String methodname="setName";
public static String[] mptypes= {"java.lang.String"};
public static Object fvalue=new String("xiaolin");
public static Object mp1=new String("xiaohong");
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
Class c=Class.forName(classname);//根据类名字符串获得类对应的Class实例
//第一种用反射创建类对象的方法相当于调用类的无参数构造方法
Object o=c.newInstance();//Student o=new Student();
//使用反射访问类对象的属性给属性设置值获取属性的值
Field f=c.getDeclaredField(fieldname);//根据Field名获得Field对象
f.setAccessible(true);
f.set(o,fvalue);//o.name="xiaolin";使用反射给o对象的f代表的属性设置值为发value的值
System.out.println(f.get(o));//获取o对象的f属性对应的值并输出
@SuppressWarnings("unchecked")
//使用反射调用对象的方法
//使用反射根据方法名和参数类型参数数量来获取具体某个方法
Method m=c.getDeclaredMethod(methodname, Class.forName(mptypes[0]));//String.class
//方法的调用调用o对象的m方法方法的实际参数是mp1mo是方法调用的返回值
Object mo=m.invoke(o,mp1);//o.setName("xiaohong");
System.out.println(mo);
//调用了o对象名为setAge参数有1个类型是int型的方法实际参数是21
m=c.getDeclaredMethod("setAge", int.class);
m.invoke(o, 21);
System.out.println(o);
/*Method m=c.getDeclaredMethod(methodname);
Object mo=m.invoke(o);
System.out.println(mo);
System.out.println(f.get(o));*/
@SuppressWarnings({ "unchecked", "rawtypes" })
//第二种用反射创建类对象的方法先获取具体的Constructor再用Constructor去创建对象
Constructor con=c.getDeclaredConstructor(String.class,int.class);//根据构造方法参数类型来获取某个构造方法
Object o1=con.newInstance("Mary",20);
//用Constructor创建类对象相当于Student o1=new Student("Mary",20);
System.out.println(o1);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

BIN
Java/img/16d07a728bb36516 Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
Java/img/16d07a85378a48b2 Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
Java/img/16d07aa7ab458eec Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

BIN
Java/img/20180525150314231 Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
Java/img/CLASSPATH.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
Java/img/JAVA_HOME.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
Java/img/JDK.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
Java/img/do-while.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
Java/img/for.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

BIN
Java/img/if-else.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
Java/img/while.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

View File

@ -7,7 +7,7 @@
| 赖桂彬 | 广州城市理工学院 | |
| 梁家晖 | 广州城市理工学院Datawhale成员 | https://github.com/leungkafai |
| 陈玉林 | 广州城市理工学院 | |
| 潘梓琪 | 广州城市理工学院 | |
| 潘梓琪 | | |
| 周思阳 | 武汉理工大学,物流管理硕士 | https://github.com/suifengyougu |
@ -31,41 +31,41 @@
- 组队、修改群昵称
- 熟悉打卡规则。
### Task01Java简介与环境配置2天
### Task012天
0.java简介与安装配置
1.基本数据类型与变量
### Task02初始Java语言基础2天
### Task022天
2.运算符和表达式
3.控制流程
### Task03Java数组1天
### Task031天
4.数组
### Task04面向对象编程基础3天
### Task043天
5.类与方法
6.继承与多态
### Task05面向对象核心技术3天
### Task053天
7.抽象类与接口
8.异常处理
### Task06反射与注释3天
### Task063天
9.反射
10.注解
### Task07枚举类型2天
### Task07: (2天)
11.泛型
@ -77,4 +77,4 @@
>Datawhale是一个专注于数据科学与AI领域的开源组织汇集了众多领域院校和知名企业的优秀学习者聚合了一群有开源精神和探索精神的团队成员。Datawhale以“for the learner和学习者一起成长”为愿景鼓励真实地展现自我、开放包容、互信互助、敢于试错和勇于担当。同时Datawhale 用开源的理念去探索开源内容、开源学习和开源方案,赋能人才培养,助力人才成长,建立起人与人,人与知识,人与企业和人与未来的联结。