java复习资料

文章目录

一、Java入门

Java开发环境

  • JDK: Java Development ToolKit :Java开发工具包.
  • JDK下载安装:安装JDK时,记住安装目录。
  • JDK配置(配置环境变量):
    • PATH:把JDK安装目录下的bin目录(此电脑->右键属 性->高级系统设置->环境变量)
    • JAVA_HOME:JDK的安装目录
    • CLASS_PATH:类路径(把JDK中的Java类库或者第三方的Java类库所在目录配置进来)

第一个Java程序

Java程序开发步骤:

  • 第一步:编写源代码
    新建源文件,后缀名是.java
    文本编辑器:记事本,notepad++,IDE

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

    文件名要求和文件中public修饰的类的类名相同。(如果文件中没有public修饰的类,那么文件名就没有要求)
    建议类名首字母大写

  • 第二步:编译源代码
    使用编译器javac对源代码进行编译:

    javac 源文件路径
    

    编译出的结果:Xxx.class字节码文件, xxx就是class后边的类名,字节码文件是以类为单位的,也就是一个类对应一个字节码文件

  • 第三步:加载执行
    使用解释器java对源码进行加载,虚拟机进行解释执行:java Xxx
    java解释器后边时main方法所在的类的类名

二、变量和数据类型

1.注释

注释不会执行,是一些解释说明信息。Java中的注释在编译的时候就会被忽略掉。

Java支持三种注释:

  • 单行注释

    从注释符号开始,到当前行的末尾都是注释。

    //这后边都是注释
    
  • 多行注释

    多行注释包含在/* */之间.

    /*
    这里边是多行注释
    */
    
  • 文档注释

    文档注释是一种特殊的多行注释,主要对Java中的类、方法、成员变量等进行说明。文档注释会包含在javadoc生成的文档中。

    /**
     这里是文档注释
    */
    

    一般为了更美观,建议文档 注释中每行注释前边都加一个星号。

    /**
     * 这是一行注释
     * 这又是一行注释
     */
    

2.变量

变量就代表内存中的一块存储空间,可以用来存取数据。

Java中把数据做了分类,不同类型的数据需要的存储空间大小不一样,这就要求变量必须指定数据类型。数据类型决定了变量分配多大的内存空间。

2.1 声明变量

变量声明以后,才可以使用。变量的声明包含两部分:数据类型和变量名。

数据类型 变量名;
  • 变量名

    Java中变量名、类名、方法名等等这些有程序员设置的名字叫做标识符。

    Java中标识符要求:

    • 只能是字母(中文文字)、数字、下划线和美元符号(人民币符号)
    • 不能以数字开头
    • 不同与Java关键字同名(public class static)
    • 见名知意
    • 多个单词的话,通过单词首字母大写的驼峰式或者用下划线隔开. studentName student_name
    • 建议变量名和方法名首字母小写;类名首字母大写
  • 数据类型

int age;

通过变量名age就可以进行数据的存取.

变量如果没有声明,直接使用会报错:

VariableDemo.java:6: 错误: 找不到符号
                age = 18;
                ^
  符号:   变量 age
  位置: 类 VariableDemo

2.2 变量初始化

初始化就是给变量第一次赋值。Java要求变量声明以后,必须先初始化,才能继续使用。

变量 = 值;

没有初始化,直接使用,会报错:

VariableDemo.java:8: 错误: 可能尚未初始化变量age
                age = age + 1;
                      ^
1 个错误

2.3 使用变量

变量的使用无非就是存数据和取数据。

  • 存(修改)

    变量 = 值;
    
  • 变量 + 1
    

    变量名直接就可以代表变量中的数据

public class VariableDemo {
	public static void main (String[] args) {
		//1.声明变量
		int age;
		//2.初始化
		age = 18;
		//3.使用
		age = age + 1;
		//输出
		System.out.println("年龄:" + age);
		
		System.out.println("======================");
		//Java支持变量声明的同时初始化
		int num1 = 50;
		System.out.println("1班的学生人数是" + num1);
		//Java支持可以一条语句声明多个同类型的变量
		int num2=60,num3=70;
		System.out.println("2班的学生人数是" + num2);
		System.out.println("3班的学生人数是" + num3);
		
	}
}

2.4 常量

常量相对于变量的区别:

  • 声明的时候在数据类型前边加上final

  • 常量初始化以后,再不允许修改(赋值)

  • 常量名建议全大写,多个单词下划线隔开

final 数据类型 常量名;
final int SIDE = 60;

如果常量初始化以后再次修改,会报错:

VariableDemo.java:23: 错误: 无法为最终变量SIDE分配值
                SIDE = 70;
                ^
1 个错误

Java中把10、1.5、true、‘男’、”中国“ 等字面量称为字面值常量

3.数据类型

数据类型分为基本数据类型和引用数据类型,这里研究基本数据类型和String字符串类型。

基本数据类型总共8个,分为四大类。

3.1 整形

整形包含四个:int long short byte

  • int

    基本整形,占据4字节(B),32位(b), 负的2的31次方 到 正的2的31次方-1

  • long

    长整形,占据8字节(B),64位(b), 负的2的63次方 到 正的2的63次方-1

  • short

    短整型,占据2字节(B),16位(b), 负的2的15次方 到 正的2的15次方-1 -32768 到 32767

  • byte

    字节,常用于字节数据流处理

3.2浮点型

浮点型2种:float double , 浮点型不精确,只能控制精度。

  • float

    浮点,4字节,32位

  • double

    双精度浮点 , 8字节,64位

3.3字符型

字符型:char

字符型存储的是单个字符,需要使用单引号标识(单引号 引起来)

'中'    'a'    '1'

字符中包含一些特殊字符,我们一般也叫作转义字符。

  • 不能使用一个符号进行展示的字符

    '\n'   '\r'    '\t'
    

    换行符 回车符 制表符

  • 被赋予了特殊意义的字符,不能再代表自己的字符

    '\''    '\"'     '\\'
    

    单引号 双引号 反斜线

字符会被编码为二进制码(16)进行存储。所以可以把char类型的字符当做16位的一个整数进行使用(运算)。

3.4布尔型

布尔型:boolean

boolean类型只有两个数据:true、false

3.5字符串类型

字符串类型String不是基本数据类型,是引用数据 类型,但是String的使用非常多,而且跟基本类型相似。

字符串中包含多个字符(大于等于0),双引号标识。

""    "中"    "中国"  
public class DataTypeDemo {
	public static void main (String[] args) {
		String name = "Java高级程序设计";//商品名
		int count = 100;//商品数量
		float price = 245.98f;//商品价格
		char flag = '中';//标记
		boolean isHot = true;//是否热卖品
		
		//输出 
		System.out.println("商品信息如下:");
		System.out.println("商品名称:" + name);
		System.out.println("商品数量:" + count);
		System.out.println("商品价格:" + price);
		System.out.println("商品标志:" + flag);
		System.out.println("是否热卖:" + isHot);
		
		//特殊字符
		System.out.println("换行符:" + '\n');
		System.out.println("回车符:" + '\r');
		System.out.println("制表符:");
		System.out.println("张飞"+'\t'+"张翼德");
		System.out.println("关羽"+'\t'+"关云长");
		System.out.println("李世民"+'\t'+"太宗");
		System.out.println("字符a+1是" + (char)('a'+1) );//字符b
	}
}

4.数据类型转换

4.1 字面值的类型

12      3.14

默认整形字面值当做int处理,小数字面值当做double处理。

12L     3.14F

如果整形字面值后边加个l/L,那么就当做long类型处理。小数后边加个f/F,那么 就当做float类型处理 。

注意:如果整数字面值的大小超过int的范围,就必须加上l/L。

4.2 数据类型转换

数据类型转换:自动类型转换 和 强制类型转换

  • 自动类型转换

    有些类型之间转换时会自动进行。

    根据能存储数据的范围大小进行排序,从小到大(左到右)会自动转换,从大到小需要强制转换.

    byte short (char) int long float double

  • 强制类型转换

    强制转换在要转换的数据之前加上小括号,小括号里边是目标类型。

    int age = 30;
    short sAge = (short)age;
    
public class TypeConverterDemo {
	public static void main (String[] args) {
		//自动类型转换
		short num1 = 20;
		int num2 = 80;
		long num3 = 1200;
		float num6 = 3.14F;//F作为float类型数据的标志
		double num4 = 350.99;
		
		num2 = num1;//short  -->  int
		num4 = num3;//long  -->  double
		
		//强制类型转换
		num2 = (int)num4;//double -->  int  需要强制转换
		float num5 = (float)1.5;//double  --->  float
		long num7 = 10000000000L;//L作为long类型数据的标志
	}
}

注意:做运算时,比int低的类型先自动上升为int类型,然后再进行运算。也就是运算结果最低都是int类型。

byte b = 1;
short s = 2;
int i = b + s;//结果是int类型

三、Java中的运算符

1.算术运算符

主要对数值型进行运算。

+    -    *    /      %   

都是双目运算符,也就是有两个操作数。同类型进行运算,如果不同类型,默认把小类型上升为大类型。结果还是这种类型。

注意:

  • 除法/ 要注意结果是同类型的问题。 1/2的结果是0
  • 取余% 也叫作取模。取余运算的结果是有规律的(跟除数有关)。 给a取余,结果是0到(a-1)。
    • 取余可以用来判断整除(余数是0)
    • 约束数据的范围 [m,n] [0,n-m] + m %(n-m+1) + m
++    --

自增自减运算符。单目运算符(只有一个操作数),但是要求唯一的操作数必须是变量。因为自增(减)运算是给变量加(减)1。

++a    --a      a++   a--

等价于

a = a + 1; 
a = a - 1;

前自增(减) 和 后自增(减) 的区别:

  • 前后的相同点:都会给变量加(减)1

  • 前后的区别主要体现在运算结果不一样

    int r = ++a;
    int r2 = a++;
    
    • 前自增(减):先给变量加(减)1; 然后取变量中的值作为运算结果.
    • 后自增(减):先取变量中的值作为运算结果; 然后给变量加(减)1.
public class SelfAddDemo {
	public static void main (String[] args) {
		//自增自减运算
		int num1 = 10;
		int num2 = 10;
		System.out.println("自增之前:num1="+num1+",num2="+num2);
		int r1 = ++num1;
		int r2 = num2++;
		System.out.println("自增之后:num1="+num1+",num2="+num2);//11,11
		System.out.println("自增结果:r1(前)="+r1+",r2(后)="+r2);//10,11
		
		int num3 = 10;
		int r3 = num3++ + --num3 - num3--  + ++num3;
		//num3   11       10       9         10     
		//结果   10       10       10        10
		System.out.println("num3="+num3);//10
		System.out.println("r3="+r3);//20
		
	}
}

2.赋值运算符

赋值运算符主要用来给变量赋值。

a = 1;

把右边的值赋值给左边的变量,要求左边必须是变量。

组合赋值运算符:把算术运算符(位运算符) 和 赋值运算符进行组合,先做算术运算,再做赋值运算。

+=    -=  *=   /=   %=   
a += 1;  等价于   a = a + 1;
public class SwapDemo {
	public static void main (String[] args) {
		//交换两个变量的值
		int a=1,b=2;
		System.out.println("交换之前:a="+a+",b="+b);
		int tmp = a;
		a = b;
		b = tmp;
		System.out.println("交换之后:a="+a+",b="+b);
		//可以借助算术运算实现交换(运算中产生的数据不能超过int范围)
		a += b;
		b = a - b;
		a -= b;
		System.out.println("再交换之后:a="+a+",b="+b);
		
	}
}

3.关系运算符

关系运算表述两个数据的某种大小关系是否成立。成立结果是true;否则结果是false;

>   <   >=   <=   ==   != 
a > b
a == b

注意:

  • 关系运算只针对于基本数据类型的数据。(字符串String类型的数据不要用)
  • 运算结果是boolean类型

4.逻辑运算符

逻辑运算是表述两个boolean类型之间的逻辑关系。

&&   ||    !    ^(异或)      &    |

注意:

  • 逻辑运算只能操作boolean类型的数据
  • 逻辑运算的结果还是boolean
&&(与)truefalse
truetruefalse
falsefalsefalse
||(或)truefalse
truetruetrue
falsetruefalse
^(异或)truefalse
truefalsetrue
falsetruefalse

关于逻辑与和逻辑或的短路特性: && || 有短路特性;& | 没有短路特性

  • 建议使用带短路特性的&& ||
  • 短路:左边的操作数如果能决定最终的运算结果,那么右边不做运算。 对&&来说,左边是false,会短路;对||来说,左边是true,会短路。

5.条件运算符

条件运算符作用: 根据条件的真假,从两个数据中选择一个作为结果。

条件?数据1:数据2

结果: 条件为true,数据1作为结果; 否则以数据2作为结果。

注意:

  • 条件必须是boolean,在问号前边
  • 数据1和数据2必须同类型,处于冒号两边
public class OperatorDemo3 {
	public static void main (String[] args) {
		//从两个整数找出较大的
		int a=10,b=30;
		int max = a>b?a:b;
		System.out.println(a+"和"+b+"中较大的是:" + max);
		//处理非法值:成绩中负数(非法值)都当做0处理.
		int score = -1;
		score = score>=0?score:0;
		System.out.println("成绩是:" + score);
		//总共有total行数据,每页可以显示size行,计算总共需要多少页才能全部显示
		int total = 100;
		int size = 10;
		int pages = total/size;
		pages = total%size==0?pages:pages+1;
		System.out.println("每页"+size+"行,"+total+"行需要" + pages + "页");
		
	}
}

6.位运算符

对数据的二进制位直接进行运算。

&(位与)  |(位或)   ^(位异或)   ~(位取反)    <<(左移)   >>(右移:空出来的位置补符号位)   >>>(右移,空出来的位置补0)

四、选择结构

Java中的流程控制结构:

  • 顺序结构

    代码按照从上往下的顺序一行行执行.

  • 选择结构

    根据条件的真假,选择其中一个分支的代码块执行.

  • 循环结构

    控制代码块循环多次执行,条件控制循环的次数.

1.系统的输入输出

1.1 系统输入System.in

Java中的系统输入默认绑定的是键盘输入缓冲器,系统输入可以从缓冲器读取键盘输入的数据。

直接使用System.in读取键盘输入的数据比较麻烦,Java提供了Scanner这个工具,可以封装系统输入,更简单方便。

Scanner读取键盘输入的步骤:

  • 导入Scanner
  • 实例化Scanner对象
  • 调用Scanner对象的nextXxx方法读取数据
    • nextInt
    • nextLong
    • nextShort
    • nextByte
    • nextFloat
    • nextDouble
    • nextBoolean
    • next 字符串String
    • nextLine 读一行,遇到空格不停,遇到换行(回车)才停
  • 关闭资源(用完了)
//1.import导入Scanner类
import java.util.Scanner;
public class SystemInDemo {
	public static void main (String[] args) {
		//2.实例化Scanner对象
		Scanner input = new Scanner(System.in);//input变量代表了Scanner对象
		//3.调用方法读取键盘输入的数据
		System.out.print("请输入一个整数:");
		int num = input.nextInt();//nextXxx方法返回读取到的数据,nextXxx方法都是阻塞函数,会停住等待键盘输入
		
		//输出
		System.out.println("读取到的数据是:" + num);
		System.out.println("==================================");
		System.out.print("请输入姓名和年龄(空格隔开):");
		String name = input.next();
		int age = input.nextInt();
		//输出
		System.out.println("我叫:" + name + ",年龄" + age);
		
		//4.关闭资源
		input.close();			
	}
}

注意:

  • 键盘输入数据结束时,必须回车(\n换行),因为遇到换行才会刷新输入缓冲器,才会读取数据
  • 输入数据的类型匹配问题:
    • 可以读取数据之前,System.out输出一个提示信息(治标不治本)
    • 在读取之前判断是不是需要的类型(预防)
    • 类型错误以后,再处理错误
  • 键盘输入数据时,如果一次输入多个数据,那么数据之间默认空格隔开(分隔符可以修改)
  • 如果输入字符串时,字符串中就包含空格符,解决办法:修改分隔符。或者使用nextLine.

1.2 系统输出System.out

系统输出用来把数据输出到console控制台.

System.out的主要输出方法:

  • println 输出最后会自动加上换行
  • print 最后没有换行
  • printf 格式化输出
    • %s 字符串
    • %d 十进制整数
    • %o 八进制整数
    • %x 十六进制整数
    • %g 十进制浮点数
    • %04d : 4代表输出的数据占据几位。不够默认补空格。0代表不够补0
    • %.4f : .4代表小数点后边保留4位
public class SystemOutDemo {
	public static void main (String[] args) {
		//系统输出
		System.out.print("这是一行\n");
		System.out.println("这是下一行");
		String name = "张飞";
		int age = 20;
		System.out.printf("姓名:%s,年龄:%d\n",name,age);//格式化输出,第一个参数定义输出格式,后边的参数是给格式中的占位符填充数据
		int num1 = 15;
		double num2 = 3.1415926;
		int num3 = 0xf;
		int num4 = 017;
		int num5 = 0b1111;
		System.out.printf("%04d\n",num1);//0015
		System.out.printf("%o\n",num1);//17
		System.out.printf("%x\n",num1);//f
		System.out.printf("%.2f\n",num2);//3.14
		System.out.println(num3 + "," + num4 + "," + num5);//
	}
}

注意:Java中整数字面值默认十进制,0x开头的是十六进制;0开头的是八进制;0b开头的是二进制。

2.选择结构

选择结构是把代码的执行分为两个或者多个支路,通过条件选择其中一个支路执行。所以选择结构也叫做分支结构。

Java中选择结构有两种: if switch

2.1 if…else…

if…else…是否代码的执行分为两条支路,条件为true,执行if后的支路;否则执行else后边的支路。

语法:

if(条件){
	//if支路的代码块
}else{
    //else支路的代码块
}
import java.util.Scanner;
public class IfElseDemo {
	public static void main (String[] args) {
		Scanner input = new Scanner(System.in);//input变量代表了Scanner对象
		
		//从两个数中找出较大的数
		System.out.print("请输入两个整数:");
		int num1=input.nextInt(),num2=input.nextInt();
		int max;//较大的
		if(num1>num2){
			max = num1;
		}else{
			max = num2;
		}
		
		/*
		int max = num1;
		if(num1<num2){
			max = num2;
		}*/
		
		System.out.println(num1+"和"+num2+"中较大的数是:" + max);
		
		System.out.println("=======================================");
		//成绩如果为负值,当作0处理
		System.out.print("键盘输入成绩:");
		int score=input.nextInt();
		if(score<0){
			score = 0;
		}
		
		System.out.println("成绩是:" + score);
		
		System.out.println("=======================================");
		if(num1>0)
			System.out.println("正数");
		else
			System.out.println("非正数");
		
	}
}

注意:

  • 条件结果必须是boolean类型

  • else支路的代码块如果是空的,else可以省略

  • 如果if或者else中的代码块只有一行(或者是一个结构),那么大括号可以省略(不建议)

2.2 if…else…的嵌套

if或者else中还可以再嵌套if…else…

if(){
	if(){	
	}else{	
	}
}else{
	if(){	
	}else{	
	}
}
2.2.1 基本嵌套方式
import java.util.Scanner;
public class MaxDemo{
	public static void main(String[] args){
		Scanner input = new Scanner(System.in);
		//从三个数中找出最大的数
		System.out.print("请输入三个整数:");
		int a = input.nextInt(),b = input.nextInt(),c = input.nextInt();
		//先看第一个数是否是最大的
		if(a > b && a > c){//a是最大的
			System.out.println(a + "是最大的");
		}else{//a不是最大的
			//再看b是否是最大的
			if(b>c){
				System.out.println(b + "是最大的");
			}else{
				System.out.println(c + "是最大的");
			}			
		}
		/**
		if(a>b){
			if(a>c){//a
			}else{//c
			}
				
		}else{
			if(b>c){//b
			}else{//c
			}
		}**/			
	}
}
2.2.2 特殊嵌套结构(多条件if)

多条件if是一种特殊的嵌套结构,特殊的地方:

if(条件1){
	//...
}else if(条件2){
	//...
}else if(条件n){
	//...
}else{
	//...
}
  • 只有else中嵌套了新的if…else…
  • else中只嵌套了一个if…else…,再没有其它代码
  • 这种情况可以简化嵌套结构
  • 常用于同一种条件的多分支(多区间)的判断
import java.util.Scanner;
public class IfElseIfElseDemo{
	public static void main(String[] args){
		Scanner input = new Scanner(System.in);
		//从三个数中找出最大的数
		System.out.print("请输入三个整数:");
		int a = input.nextInt(),b = input.nextInt(),c = input.nextInt();
		//先看第一个数是否是最大的
		if(a > b && a > c){//a是最大的
			System.out.println(a + "是最大的");
		}else if(b>c){
			System.out.println(b + "是最大的");
		}else{
			System.out.println(c + "是最大的");
		}			
		
	}
}

2.3 switch…case

switch…case这种选择结构是一种特殊的多条件选择结构,特殊的地方:

  • 多条件必须是同一个表达式等于不同的几个常量值的判断

    if(a==1){
    	//代码块1
    }else if(a==2){
    	//代码块2
    }else if(a==3){
    	//代码块3
    }else{
    	//代码块n
    }
    

    简化为switch的语法结构

    switch(a){
    case 1:
    	//代码1
    	break;
    case 2:
    	//代码2
    	break;
    case 3:
    	//代码3
    	break;
    default:
    	//代码n
    	break;
    }
    

    执行流程:

    如果switch后边的表达式a等于第一个case后的常量1,就执行代码块1;
    如果switch后边的表达式a等于第二个case后的常量2,就执行代码块2;
    如果switch后边的表达式a等于第三个case后的常量3,就执行代码块3;
    如果switch后边的表达式a不等于任何一个case后的常量,就执行代码块n;
    
    import java.util.Scanner;
    public class SwitchCaseDemo{
    	public static void main(String[] args){
    		Scanner input = new Scanner(System.in);
    		//模拟判断方向,控制物体的移动
    		System.out.print("请输入方向:");
    		String direction = input.next();
    		final String DOWN = "s";
    		/*
    		if("w".equals(direction)){
    			System.out.println("物体往上移动");
    		}else if("d".equals(direction)){
    			System.out.println("物体往右移动");
    		}else if("s".equals(direction)){
    			System.out.println("物体往下移动");
    		}else if("a".equals(direction)){
    			System.out.println("物体往左移动");
    		}else{
    			System.out.println("物体不移动");
    		}*/
    		switch(direction){
    		case "w":
    			System.out.println("物体往上移动");
    			break;
    		case "d":
    			System.out.println("物体往右移动");
    			break;
    		case DOWN://final常量也可以
    			System.out.println("物体往下移动");
    			break;
    		case "a":
    			System.out.println("物体往左移动");
    			break;
    		//case 后边的值不能重复
    		/**  
    		case "a":
    			System.out.println("物体往左移动");
    			break;**/  
    		default:
    			System.out.println("物体不移动");
    			break;
    		}
    		
    		//switch后边只支持int、String和枚举
    		/**
    		double d = 3.15;
    		switch(d){
    		case 1.5:
    			break;		
    		}*/
    		
    		
    	}
    }
    

    注意:

    • switch后边的表达式的结果一定是int(byte、short、char)或者String或者枚举

      否则报错:

      SwitchCaseDemo.java:46: 错误: 不兼容的类型: 从double转换到int可能会有损失
                      switch(d){
                            ^
      1 个错误
      
    • case后边必须是常量: 字面值常量 或者 final修饰的常量

      否则报错:

      SwitchCaseDemo.java:28: 错误: 需要常量字符串表达式
                      case down:
                           ^
      1 个错误
      
    • case后边的常量不能重复

      否则报错:

      SwitchCaseDemo.java:34: 错误: case 标签重复
                      case "a":
                      ^
      1 个错误
      
    • 正常情况下,每个case(包括default)的代码块最后都应该加上break;语句。break可以实现case之间的互斥。

2.4 break;

break;语句的作用是结束结束当前结构的执行,也就是结束switch…case结构的执行。

注意:

  • 如果switch…case中每个case后边都不加break语句,那么当匹配上某个case以后,就从这个case中的语句开始执行,一直执行到switch…case结束。

    只有遇到break;才会结束。

  • 有极其特殊的情况下,才有可能某些case后边不加break;实现case后边代码的复用

import java.util.Scanner;
public class BreakDemo{
	public static void main(String[] args){
		Scanner input = new Scanner(System.in);
		//判断象棋某个棋子的移动规则
		System.out.print("输入棋子标记:");
		String item = input.next();
		switch(item){
		case "帅":
		case "将":
			System.out.println("只能在中间的4格中移动");
			break;
		case "兵":
		case "卒":
			System.out.println("只能往前,不能后退");
			break;
		case "象":
		case "相":
			System.out.println("只能走田,不能过河");
			break;
		case "士":
			System.out.println("只能在中间的4格中斜着移动");
			break;
		case "炮":
			System.out.println("只能直线运动,并且隔着一个子吃掉对方的子");
			break;
		case "车":
			System.out.println("只能直线运动");
			break;
		case "马":
			System.out.println("只能走日");
			break;
		default:
			System.out.println("无效标记");
			break;
		}
		
	}
}

说明: 一个case中如果没有break语句,那么就可以包含执行下一个case中的代码。

五、循环结构

循环结构是控制某个代码块循环多次执行。只要条件还为true,就继续执行一次;一旦条件为false,就结束循环。

Java中有三种循环结构: while , do…while , for

1.while

语法:

while(条件){
	//要循环多次执行的代码块
}

执行流程:

  • a.判断条件

  • b.条件为true,执行一次代码块;条件false,结束执行。

  • c.循环a,b的过程

    条件true --> 执行一次代码块—> 条件true --> 执行一次代码块) —> … —> 条件flase --> 结束

基本循环结构的四要素

  • 声明循环变量:每个循环中一般都有一个循环在变化的值,用来控制循环条件的真假变化(其实就是用来控制循环次数)。
  • 循环条件:一般循环条件是个表达式,这个表达式中包含有循环变量
  • 要循环多次执行的代码块
  • 循环变量的变化
public class WhileDemo{
	public static void main(String[] args){
		//循环输出1到100
		//把输出一个整数的语句循环执行100次
		int i = 1;//声明循环变量(计数器)
		while(i<=100){//循环条件
			System.out.print(i + " ");//循环执行的代码块
			++i;//循环变量的变化
		}
	}
}

注意:

  • 循环条件的结果必须boolean类型
  • 循环变量的变化不要忘了(++i),不然死循环

2.do…while

2.1 语法:

do{
	//循环执行多次的代码块
}while(条件);

执行流程:

  • a.先执行一次代码块

  • b.然后判断条件

  • c.条件是true,执行一次代码块;条件是false,退出循环

  • d.循环b,c的过程

    执行一次代码块—> 条件true --> 执行一次代码块) —> … —> 条件flase --> 结束

2.2 do…while和while的区别:

  • do…while先执行一次循环体,才开始判断条件。循环体至少执行一次.
  • while先判断条件,决定是否执行代码块。while有可能循环体一次都不执行.

使用场景:

  • 如果一个循环问题,他的代码块至少执行一次,就选择do…while
  • 如果一个循环问题,他的代码块有可能一次都不执行,就选择while
import java.util.Scanner;
public class DoWhileDemo{
	public static void main(String[] args){
		Scanner input = new Scanner(System.in);
		//计算n的阶乘
		int n = 5;
		int result = 1;//初始值1
		int i = 1;//声明循环变量
		do{
			result = result * i;//循环执行的代码块
			++i;//循环变量的变化
		}while(i<=n);//循环条件
		System.out.println(n+"的阶乘是:" + result);
		
		System.out.println("====================");
		//模拟玩游戏
		String is;
		do{
			System.out.println("玩一局游戏");
			System.out.print("是否继续(y/n):");
			is = input.next();
		}while("y".equals(is));
		System.out.println("结束退出");
		
	}
}

注意:

  • do…while中while条件小括号后边的分号不能省略。

2.3 Random

Random可以用来生成随机数.

使用步骤类似Scanner:

  • import导入Random
  • 实例化Random对象
  • 调用nextXxx方法,生成对应类型的随机数
import java.util.Scanner;
import java.util.Random;
public class GuessDemo{
	public static void main(String[] args){
		Scanner input = new Scanner(System.in);
		Random rand = new Random(System.currentTimeMillis());//以系统时间作为随机种子
		//模拟数字炸弹
		//生成一个随机数,作为目标数字
		int num = rand.nextInt(100);//[0,100)
		//循环猜测
		int min = 0;//下限
		int max = 100;//上限
		int guess;
		do{
			System.out.print(min + "到" + max + ":");
			guess = input.nextInt();//猜
			if(guess > num){//太大了,当前数作为下一次的上限
				max = guess;
			}else if(guess < num){//太小了,当前数作为下一次的下限
				min = guess;
			}				
		}while(guess != num);//没猜对,继续循环
		
		System.out.println("猜对了,就是"+num);
	}
}

变量作用域问题:

  • 局部变量的作用域是:包围这个变量声明语句的最内层的大括号。

    作用域:就是只能在这个范围中使用。

3.for

for循环是对while循环结构的简化, 不管是执行流程,还是使用场景都跟while类似。

循环结构的基本四要素:

  • 声明循环变量
  • 循环条件
  • 循环执行的代码块
  • 循环变量的变化

语法:

for(1;2;4){
	3
}

一般情况下:

  • 1的位置是声明循环变量
  • 2的位置是循环条件
  • 3的位置是循环执行的代码块
  • 4的位置是循环变量的变化

执行流程:

  • a.先执行位置1的代码(只执行一次),一般是循环变量的声明或者初始化
  • b.然后执行位置2的循环条件
  • c.如果条件是true,先执行位置3的代码块,紧跟着执行位置4的代码。(位置4一般是循环变量的变化 ,也就是赋值语句,不能是System.out之类的语句)
  • 循环b,c的过程
import java.util.Scanner;
public class ForDemo{
	public static void main(String[] args){
		Scanner input = new Scanner(System.in);
		//计算n的阶乘
		System.out.print("请输入一个正整数:");
		int n = input.nextInt();
		//  个位 : n/1%10   十位: n/10%10   百位:  n/100%10  千位: n/1000%10
		for(int i=1;n/i!=0;i*=10){
			int wei = n/i%10;			
			System.out.println(wei);
		}
		
	}
}

注意:

  • for循环的四部分都可以为空,但是小括号中的两个分号不能少。
    • 位置1为空,也就是可以把循环变量的声明放到for的外边,像while一样
    • 位置4为空,也就是把循环变量的变化又重新放回到循环体的最后一句。
    • 位置2为空,也就是循环条件为空,代表循环条件为永真。会造成死循环。
  • 最简单的死循环
import java.util.Scanner;
public class ForDemo2{
	public static void main(String[] args){
		Scanner input = new Scanner(System.in);
		//输出1到100之间所有的偶数
		int i=1;//应该放在位置1的代码
		for(;i<=100;){
			if(i%2==0){
				System.out.print(i + " ");
			}
			++i;//应该放在位置4的代码
		}
		System.out.print("\n========================\n");
		for(;;);//这是死循环(最简单的for死循环)
		//while(true);
		//do{}while(true);=
	}
}
  • 关于for中位置1声明的变量的作用域问题

    位置1声明的变量只能在for结构中使用.

public class ForDemo3{
	public static void main(String[] args){
		//找出0到100以内能被12整除的最大整数
		int j;
		for(j=100;j>0&&j%12!=0;j--);//for循环小括号中声明的变量,作用域仅限于for结构中
			
		System.out.println("结果是" + j);	
	}
}

4.break

break语句的作用是结束当前结构(包括循环结构和switch…case选择结构)。

语法:

break;
//或者
break 标签名;

break;单独使用表示结束当前结构的执行;break加上标签表示结束指定的结构的执行。

使用场景:

  • 有时在执行到某一次迭代的时候,已经达到目的或者已经得到结果,这时循环没必要再继续执行了,就可以使用break结束循环。
import java.util.Scanner;
public class BreakDemo2{
	public static void main(String[] args){
		Scanner input = new Scanner(System.in);
		//从键盘输入一个正整数,判断是否是质数(素数)
		//不能被2到n-1(其实只需要到n的平方根即可)整除
		System.out.print("输入一个正整数:");
		int n = input.nextInt();
		boolean is = true;//结果,默认是质数
		for(int i=2;i<=Math.sqrt(n);++i){
			if(n%i==0){//已经得到结果,不是质数
				is = false;
				break;
			}	
		}
		
		if(is){
			System.out.println(n + "是质数");
		}else{
			System.out.println(n + "不是质数");
		}
			
	}
}
  • 有时循环正常的循环条件不好找,但是循环退出的条件比较明显,这时可以把循环条件写为true死循环,然后在需要退出循环时使用break;
import java.util.Scanner;
public class BreakDemo3{
	public static void main(String[] args){
		Scanner input = new Scanner(System.in);
		//从键盘循环输入多个成绩,计算平均成绩。如果输入-1代表结束
		int score;
		int total = 0;
		int count = 0;
		while(true){//死循环
			System.out.print("请输入成绩:");
			score = input.nextInt();
			if(score == -1){//-1的时候,break结束循环
				break;
			}
			total += score;
			count++;
		}
		
		System.out.println("总成绩:" + total + ",总个数:" + count + ",平均成绩:" + total*1.0/count);
			
	}
}

5.continue

continue并不结束循环的执行。continue是跳过当次迭代后边剩余的语句,直接又去判断条件,开始下一次迭代。

while(条件){
	//(1)
	if(条件){
		continue;
	}
	//(2)
}

continue的作用: 就是当执行到continue的时候,会跳过continue后边位置(2)的代码,直接再去判断循环条件,做下一次迭代。

import java.util.Scanner;
public class ContinueDemo{
	public static void main(String[] args){
		//输出1到100之间的奇数
		for(int i=1;i<=100;i++){
			if(i%2==0){//如果是偶数,跳过输出.继续下一个
				continue;
			}
			System.out.print(i + " ");
		}
			
		System.out.print("\n========================\n");
		for(int i=1;i<=100;i++){
			if(i%2!=0){
				System.out.print(i + " ");
			}
		}
			
	}
}
  • 很多时候,只要稍作逻辑的变化,既可以避免使用continue

6.Math

Math工具类中包含了大量的数学运算的工具方法:

  • Math.sqrt(n) 平方根
  • Math.pow(x,y) x的y次方
  • Math.abs(n) n的绝对值

7.循环嵌套

一个循环中再嵌套另一个循环。也就是循环中的循环体也需要循环去处理。

以双重循环为例:

while(){
	//
	while(){
	
	}
	//
}
public class MultiLoopDemo{
	public static void main(String[] args){
		//计算1! + 2! + 3! + 4! + ... + 10!
		int sum = 0;
		for(int i=1;i<=10;i++){
			//计算i的阶乘
			int jie = 1;
			for(int j=1;j<=i;j++){
				jie *= j;
			}
			sum += jie;//求和
		}
		System.out.println("1到10的阶乘之和是:" + sum);
	}
}

双重循环经常可以用来输出二维图形: 直角三角形、九九乘法表

1*1=1
1*2=2 2*2=4
......
1*9=9 2*9=18 ......  9*9=81
for(int i=1;i<=9;i++){
    for(int j=1;j<=i;j++){
        System.out.print(j + "*" + i + "=" + (j*i) + "\t");
    }
    System.out.println();
}

关于break;或者continue;在循环嵌套中的使用:

  • break 加上标签名可以直接退出指定循环的执行。

    import java.util.Scanner;
    public class MultiLoopDemo3{
    	public static void main(String[] args){
    		Scanner input = new Scanner(System.in);
    		/**
    		1 2 3 4 5 6 7 8 9 10
    		1 2 3 4 5 6 7 8 9 10
    		1 2 3 4 5 6 7 8 9 10
    		1 2 3 4 5 6 7 8 9 10
    		1 2 3 4 5 6 7 8 9 10
    		**/
    		//外层控制 5行
    		label1:for(int i=1;i<=5;i++){
    			//打印一行
    			label2:for(int j=1;j<=10;j++){
    				System.out.print(j + " ");
    				if(i%4 == 0 && j%8 == 0){
    					break label1;//结束label1指示的循环
    				}
    			}
    			System.out.println();
    		}					
    	}
    }
    

六、数组

数组可以用来存储一组同类型的数据。

一个数组代表的是内存中连续的一串内存空间,所以可以存储多个同类型数据。

概念:

  • 数组的元素:数组中存储的每个数据叫做数组的一个元素。

1.创建数组

创建数组就是分配内存空间。内存空间由元素的类型和个数决定。所以创建一个数组,核心的两个要素就是元素类型和元素个数。

语法:

new 元素类型[元素个数];
new int[7];

说明: 数组的长度(也就是元素个数)一旦确定,不能修改。也就是数组长度不可变。

2.引用数组

要使用数组,必须先声明一个数组类型的变量,引用到这个数组才可以。

通过引用了数组的这个变量,就可以访问到数组。

数组类型的语法:

元素类型[]
int[]

声明数组类型变量的语法:

元素类型[]  变量名;

正常情况下,先声明变量,再创建数组,然后赋值(就是让变量引用数组)。

比如:

int[] arr;
arr = new int[7];

等价于

int[] arr = new int[7];

3.访问数组

访问数组主要是访问数组中的元素。

访问数组中的元素通过元素的下标访问,下标从0开始,最后一个元素的下标是数组长度-1。

语法:

数组名[下标]
arr[0]
arr[6]

每个元素就相当于一个普通变量,无非就是赋值和取值。

经常也需要访问数组的长度,数组提供了一个属性length代表长度:

数组名.length
arr.length
public class ArrayDemo{
	public static void main(String[] args){
		//1.创建数组,并声明数组变量引用之
		int[] arr = new int[5];
		//2.访问数组中的元素
		arr[0] = 10;
		arr[1] = 11;
		arr[2] = 12;
		arr[3] = 13;
		arr[4] = 14;
		System.out.println(arr[0] + "," + arr[1] + ","
		+ arr[2] + "," + arr[3] + "," + arr[4]);
		//3.如果要依次对数组中的每个元素做同样的操作,叫做遍历数组.使用循环
		for(int i=0;i<=arr.length-1;i++){
			System.out.print(arr[i]);
			if(i<arr.length-1){
				System.out.print(",");
			}
		}
			
	}
}

下标如果超出0到length-1的范围,会报错:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 6
        at ArrayDemo.main(ArrayDemo.java:7)

4.数组中元素的初始化问题

数组中的元素在创建数组的时候就自动初始化好了。

  • 整形(包括char)元素自动初始化为0
  • 浮点型元素自动初始化为0.0
  • 布尔类型元素自动初始化为false
  • 引用数据类型(String)自动初始化为null

也可以自己在创建数组的时候指定每个元素的初始值。支持两种语法:

  • 在创建数组的同时给出所有初始值.

    new 元素类型[]{元素1,元素2,元素3,...,元素n};
    
    new int[]{11,12,13,14,15};
    

    注意:方括号中一定不能写长度。长度是根据给的初始值的个数确定的.

  • 在声明数组变量的同时创建数组,并给出每个元素的初始值

    元素类型[] 变量 = {元素1,元素2,元素3,...,元素n};
    
    int[] arr = {11,12,13,14,15};
    
public class ArrayInitDemo{
	public static void main(String[] args){
		//1.创建数组,并声明数组变量引用之
		int[] arr = new int[5];
		//整形数组默认初始化为全0
		for(int i=0;i<=arr.length-1;i++){
			System.out.print(arr[i]);
			if(i<arr.length-1){
				System.out.print(",");
			}
		}
		System.out.print("\n===========================\n");
		//在创建数组的时候,给出每个元素的初始值
		int[] arr2 = new int[]{10,11,12,13,14};
		arr2 = new int[]{20,21,22,23,24};
		for(int i=0;i<=arr2.length-1;i++){
			System.out.print(arr2[i]);
			if(i<arr2.length-1){
				System.out.print(",");
			}
		}
		System.out.print("\n===========================\n");
		//在声明数组变量的同时创建数组并给出每个元素的初始值
		int[] arr3 = {100,110,120,130,140};
		//arr3 = {100,210,220,230,240}; 没有在声明同时,所以不允许
		for(int i=0;i<=arr3.length-1;i++){
			System.out.print(arr3[i]);
			if(i<arr3.length-1){
				System.out.print(",");
			}
		}
			
	}
}

5.声明数组变量的语法问题

声明数组变量时,方括号可以写在变量名的前边;也可以写在变量名的后边。

元素类型[] 变量名;
元素类型 变量名[];
int[] arr;
int arr2[];

练习: 键盘录入5个学生成绩,存储到数组中。计算平均成绩。

练习:直接初始化一个数组{13,24,56,-1,35,100},统计数组中有多少个负数。

6.ForEach循环

ForEach循环是for循环的一种变形,并且只能用于对数组(集合、列表)进行遍历。

语法:

for(元素类型 变量名 : 数组){
	//
}
int[] arr = {1,3,6,10};
for(int a : arr){
	System.out.println(a);
}

这种ForEach循环,每次迭代会自动取出数组中的元素,赋值给变量a。

这种ForEach循环有缺陷,不能对元素做修改操作。

7.查找算法和排序算法

7.1 查找算法

从数组中找出某个目标数所在的位置。

  • 遍历

    遍历数组,一个一个比较。

    import java.util.Scanner;
    public class SearchDemo{
    	public static void main(String[] args){
    		Scanner input = new Scanner(System.in);
    		int[] arr = {23,45,1,10,100,50};
    		System.out.print("请输入一个整数:");
    		int key = input.nextInt();
    		//遍历查找,如果找打了,结果是下标。如果没找到,就输出没找到
    		int index = -1;//-1代表没找到
    		for(int i=0;i<=arr.length-1;i++){
    			if(arr[i] == key){//找到了
    				index = i;
    				break;
    			}
    		}
    		if(index >= 0){
    			System.out.println("找到了,下标是:" + index);
    		}else{
    			System.out.println("没找到");
    		}
    			
    	}
    }
    
  • 二分

    二分是对有序的数组进行查找。

7.2 排序算法

排序就是对数组中元素进行升序或者降序的排列。

  • 选择排序

    练习: 从一个数组中找出最大值

    public class SelectSortDemo{
    	public static void main(String[] args){
    		int[] arr = {12,57,2,6,100,88};
    		/*
    		//找出最大值
    		int max = arr[0];//初始化下标0位max最大值
    		//从下标1开始,以此跟max比较,大的放在max中
    		for(int i=1;i<=arr.length-1;i++){
    			if(arr[i] > max){
    				max = arr[i];
    			}
    		}
    		System.out.println("最大值是:" + max);
    		*/
    		//选择排序,以降序为例(从大到小)
    		//0. 从数组(0到length-1)找出最大值,放到0下标
    		//1. 从数组(1到length-1)找出最大值,放到1下标
    		//2. 从数组(2到length-1)找出最大值,放到2下标
    		//。。。。。。
    		//length-2. 从数组(length-2到length-1)找出最大值,放到length-2下标
    		
    		for(int i=0;i<=arr.length-2;i++ ){			
    			for(int j=i+1;j<=arr.length-1;j++){
    				if(arr[j] > arr[i]){//大的留在擂台,小的回到底下位置
    					//交换
    					int tmp = arr[i];
    					arr[i] = arr[j];
    					arr[j] = tmp;
    				}
    			}		
    		}
    		
    		for(int i=0;i<=arr.length-1;i++){
    			System.out.print(arr[i] + " ");
    		}
    	}
    }
    
  • 冒泡排序

  • 插入排序

  • 快速排序

8.Arrays

Arrays工具类中提供了大量的处理数组的方法,包括复制数组,二分查找,快速排序等等.

  • Arrays.sort()

  • Arrays.toString()

  • 等等

9.多维数组

多维数组 就是 数组总存储的元素还是一个一个数组。 也就是元素类型也是数组类型的数组,称为多维数组。

严格意义上说,Java中其实只有数组,没有多维数组。因为Java的多维数组其实就是元素类型比较特殊而已。

以二位数组为例讲解。

9.1创建二位数组

语法:

创建二位数组的语法:第一个方括号中写二维数组的长度。

int[][] arr = new int[5][];

创建好二位数组以后,一定要创建包含的每个一维数组。

arr[0] = new int[4];
arr[1] = new int[3];
arr[2] = new int[5];
arr[3] = new int[2];
arr[4] = new int[1];

9.2访问二维数组

访问二位数组,主要访问的是二维数组中的一维数组中的元素。

arr[二维的下标][一维的下标]
arr[0][0]
arr[1][2]
public class BinaryArrayDemo{
	public static void main(String[] args){
		//创建二维数组
		int[][] arr = new int[3][];
		arr[0] = new int[3];
		arr[1] = new int[2];
		arr[2] = new int[1];
		//访问二维数组
		arr[0][0] = 3;
		arr[0][1] = 2;
		arr[0][2] = 1;
		arr[1][0] = 2;
		arr[1][1] = 1;
		arr[2][0] = 1;
		//遍历
		//外层循环遍历二维数组
		for(int i=0;i<=arr.length-1;i++){
			//内层循环遍历一维数组
			for(int j=0;j<=arr[i].length-1;j++){
				System.out.print(arr[i][j] + " ");
			}
			System.out.println();
		}
			
	}
}

9.3声明创建的同时初始化

二维数组也支持在创建或者声明数组的同时,给数组元素进行初始化。而且支持二维和一维同时初始化。

public class BinaryArrayInitDemo{
	public static void main(String[] args){
		//创建二维数组的同时,给二维数组初始化
		int[][] arr = new int[][]{new int[3], new int[2], new int[1]};
		//创建二维数组的同时,给二维数组和一维数组都初始化
		int[][] arr2 = new int[][]{new int[]{3,2,1}, new int[]{2,1}, new int[]{1}};
		//更简单的语法(必须在声明数组变量的同时)
		int[][] arr3 = {new int[3], new int[2], new int[1]};
		int[][] arr4 = {
			{3,2,1},
			{2,1},
			{1}
		};
		
		for(int i=0;i<=arr4.length-1;i++){
			for(int j=0;j<=arr4[i].length-1;j++){
				System.out.print(arr4[i][j] + " ");
			}
			System.out.println();
		}
		System.out.println("============================");
		//ForEach遍历二维数组
		for(int[] a : arr4){
			for(int b : a){
				System.out.print(b + " ");
			}
			System.out.println();
		}
			
	}
}

9.4声明数组变量的语法问题

声明数组变量时,方括号可以在变量名前边或者后边。

int[][] arr;
int arr[][];
int[] arr[];

练习: 杨辉三角形

      1
     1 1
    1 2 1
   1 3 3 1
  1 4 6 4 1
 1 5 10 10 5 1
。。。。。。。。。。

二维数组存储杨辉三角形

1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
............

9.5二维数组的语法糖

如果二维数组中包含的所有一维数组的长度是一样的,这时可以简化语法,在创建二维数组的同时就可以创建好所有一维数组。

int[][] arr = new int[二维数组的长度][一维数组的长度];
int[][] arr = new int[3][5];

七、方法

1.概念

方法是对一个功能单元的封装。也就是方法把一个功能模块的代码提取出来,封装起来,需要使用这个功能时,直接调用该方法即可。

方法的优点:

  • 有利于代码复用。功能代码只需要编写一次,可以重复多次调用.
  • 方法的封装可以隐藏功能的具体实现方式。调用者只需要知道方法的功能和调用方式即可,不需要知道功能如何实现的。
  • 有利于简单的模块化。可以把复杂功能逻辑拆分为多个简单的功能单元,以便实现和后期的维护。

2.方法的定义

定义方法就是声明方法的原型,并实现方法的功能。

语法:

public static 返回结果的数据类型 方法名 (参数列表) {
	//可执行的代码块,也叫作方法体。就是实现方法的功能
}
public static int add (int a, int b) {
	return a+b;
}

说明:

  • public static 不是必须的,但是现阶段必须写上。后续讲解。

  • 返回结果的数据类型:这里需要一个数据类型,也简称为返回类型。

    就是指定方法最后返回的结果数据的类型。如果没有返回结果,写一个void。

  • 方法名:跟变量名一样,都是标识符,一般建议方法名首字母小写.

  • 参数列表:参数列表是定义调用时要传递给方法的数据的类型和个数。可以为空。

  • 方法体:就是可执行的代码块,用来实现方法的功能。

  • 一般把方法体,也就是大括号中的内容成为方法的实现。把大括号之前的内容成为方法的原型。

3.方法的调用

方法定义好以后,就可以在需要的地方调用它。注意:方法不调用,就不执行。

语法:

方法名(参数列表)
add(10,20);

注意:

  • 如果没有参数,参数列表可以为空。小括号不能省略。

4.方法的参数

方法的参数也叫作输入数据。也就是在方法中要使用,但是由调用者提供的数据。即把外部(调用处)的数据传递到方法中。

参数分为形式参数和实际参数。

4.1 形式参数(形参)

把定义方法时参数列表中的参数,叫做形式参数。

形式参数只是告诉调用者需要传递几个什么类型的数据。

语法:

(数据类型 参数名1, 数据类型 参数名2, ... ,数据类型 参数名n)
(int a, String s, double d)
  • 形参的声明和变量的声明语法是一样的,并且形参在方法中的使用就是当做变量使用。
  • 数据类型可以是基本数据类型,也可以是引用数据类型
  • 参数名和变量名一样,都是标识符,建议首字母小写
  • 多个参数逗号隔开

4.2 实际参数(实参)

把调用方法时参数列表中的参数,叫做实际参数。

实际参数就是调用者要传递给方法的数据。

语法:

(数据1,数据2, ... , 数据n)
(10, "张三", 178.5)
  • 实参是按照形参指定的类型和顺序给的数据,所以实参要和形参一一匹配(类型和个数)。
  • 参数之间逗号隔开

5.方法的返回值

方法的返回值是方法功能实现的结果数据,要返回给调用者.

5.1 定义方法时

  • 要指定返回结果的数据类型

  • 在方法体中得到结果以后,必须使用return语句返回结果数据.

    return 结果数据;
    
  • 如果方法没有返回结果,那么返回类型就是void,然后方法体中也可以使用return语句,但是不能带结果数据。

    return;
    

5.2 调用方法时

如果有返回结果,需要接收返回的结果数据.直接把返回结果存储到变量中即可。

类型 变量 = 方法调用;
int sum = add(10,20);

6.方法调用时代码的执行流程

当代码执行到方法调用语句时:

  • 首先调转到方法定义的地方
  • 然后把实参一一赋值给形参,就是用实参给形参初始化
  • 接下来执行方法体中的代码
  • 直到遇到return语句或者方法体中代码执行完毕,会返回到方法调用的地方。如果有返回值,也会把返回值带回去。
import java.util.Scanner;
import java.util.Arrays;
public class MethodDemo{
	public static void main (String[] args){
		//请打印1到10
		//调用方法
		printNumbers();
		System.out.println("===================");
		//请再次打印1到10
		printNumbers();
		System.out.println("===================");
		//请打印所有的水仙花数
		printAllShuiXianHua();
		System.out.println("===================");
		Scanner input = new Scanner(System.in);
		System.out.print("输入一个整数:");
		int num = input.nextInt();
		//计算num的绝对值
		int r = abs(num);//实参
		System.out.println(num + "的绝对值是:" + r);
		System.out.println("===================");
		System.out.print("输入两个整数:");
		int num1 = input.nextInt();
		int num2 = input.nextInt();
		int m = max(num1,num2);
		System.out.println(num1 + "," + num2 + "中较大的是:" + m);
		System.out.println("===================");
		int[] array = {3,18,1,20,100,50};
		int max = maxArray(array);
		System.out.println(Arrays.toString(array) + "中最大值是:" + max);
		System.out.print("输入一个整数:");
		int key = input.nextInt();
		int index = searchArray(array, key);
		if(index >= 0)
			System.out.println(Arrays.toString(array) + "中"+key+"的位置是:" + index);
		else
			System.out.println("没找到");
	}
	
	
	/**
	 * 控制台输出1到10
	**/
	public static void printNumbers(){
		for(int i=0;i<10;i++){
			System.out.print((i+1) + " ");
		}
		System.out.println();			
	}
	/**
	 * 打印所有的水仙花数
	 */
	public static void printAllShuiXianHua(){
		int ge,shi,bai;
		for(int i=100;i<=999;i++){
			ge = i/1%10;
			shi = i/10%10;
			bai = i/100%10;
			if(ge*ge*ge + shi*shi*shi + bai*bai*bai == i){
				System.out.print(i + "\t");
			}
		}
		System.out.println();
	}
	
	
	
	/**
	 * 计算一个整数的绝对值
	 * @param a  指定的整数
	 * return 返回a的绝对值
	 */
	public static int abs(int a){//形参
		int result;
		//a的绝对值
		if(a>=0){
			result = a;
		}else{
			result = 0-a;
		}
		return result;//返回结果
	}
		
	/**
	 * 从两个整数中找出较大的数
	 * @param a 整数1
	 * @param b 整数2
	 * return 返回a,b中较大的
	 */
	public static int max(int a, int b)	{
		if(a>=b){
			return a;
		}else{
			return b;
		}
	}
		
	/**
	 * 从数组中查找最大值
	 * @param arr 指定数组
	 * return 返回最大的值
	 */
	public static int maxArray(int[] arr){
		if(arr == null || arr.length <= 0){
			return -100;//应该抛出异常
		}
		if(arr.length == 1){
			return arr[0];
		}
		int max = arr[0];
		for(int i=1;i<=arr.length-1;i++){
			if(arr[i] > max){
				max = arr[i];
			}
		}
		return max;	
	}
	
	/**
	 * 从数组中查找数据
	 * @param arr 指定数组
	 * @param key 要找的目标数
	 * return 返回目标数在数组中的下标位置。找不到返回-1
	 */
	public static int searchArray(int[] arr, int key){
		if(arr==null || arr.length<=0){
			return -1;
		}
		for(int i=0;i<=arr.length-1;i++){
			if(arr[i] == key){
				return i;
			}
		}	
		return -1;
	}
}

7.方法重载

重载(overload):描述的是多个方法之间的一种关系。

满足以下条件的方法可以构成重载关系:

  • 方法名形同。(同一个类中)
  • 形参列表不同。不同包括参数类型不同,或者参数个数不同。

注意:

  • 重载与方法的参数名无关,与返回值类型无关,与方法的其他修饰词也无关。

简单来说:重载其实就是同一种功能,针对不同的参数做的不同的实现。

比如:

public static int add(int a ,int b){}
public static double add(double a, double b){}

如果有重载,方法调用时:用实参和形参的匹配来选择调用哪个方法。

  • 优先当然是完全匹配
  • 有一种不完全匹配也可以调用,就是实参可以自动类型转换为形参。

像System.out中的println方法就重载了好多个。

  • println(int)
  • println(double)
  • println(String)

八、面向对象

1.类和对象

类是一种类型(类别),是为了给对象进行分类的。分类更有益于对象的管理,以及同一种对象的特征和行为的定义。因为同一种对象的特征和行为是一样的,所以直接按照类别去定义特征和行为最方便。

结论: 先应该定义类,在按照类中定义的特征和行为创建出对应类型的对象.

概念:

  • 类:类是对某一种类型的对象所共有的特征(属性/状态)和行为的抽象和描述。

    一般也把类称为对象的模板。比如: 人类、动物类、计算机类 …

  • 对象:对象是类的实例化,就是类代表的类别一个具体的实例。

    对象就是按照类这种模板造出来的实物。比如:张三这个人、tom这只猫、编号是1001这台计算机 。。。。

1.1类的定义

类的定义主要是类名,以及类中包含的成员。成员主要就是这种类别的对象所共有的属性和行为的描述。

  • 属性对应到代码中就是变量,这种变量称为成员变量.

    属性是静态的数据,所以用变量就可以存储。

  • 行为对应到代码中就是方法,也可以称为成员方法。

    行为是动态的功能,所以用方法去实现。

  • 类中还可以包括代码块

  • 类中还可以包含内部类(接口、枚举、注解)

语法:

[修饰词] class 类名 {
	//类中的成员
	//1.成员变量
	//2.方法
	//3.代码块
	//4.内部类
}
/**
 * 学生类
 */
public class Student {
	//类中的成员
	//1.成员变量(属性)
	long studentNo;//学号
	String studentName;//姓名
	String studentGender;//性别
	String studentClass;//班级
	int studentAge;//年龄
	
	//2.方法(行为)
	/**
	 * 打招呼
	 * @param other 另一个学生
	 */
	public void sayHi(String other){
		System.out.println("你好:" + other);
	}
	/**
	 * 学习
	 * @param course 指定课程
	 */
	public void learn(String course){
		System.out.println("今天学习了:" + course);
	}
	
	
	//3.代码块
	{
		//多行可执行的代码
	}
	
	//4.内部类
	class StudentInner{}
}

注意:

  • 类名是标识符,建议首字母大写
  • 所有的方法都先不要加static关键字
  • 代码块和内部类后续讲解

1.2实例化对象

类定义好以后,就可以按照类(模板)去实例化一个对象,那么对象中就包含了类中给定义的成员。

实例化对象的语法:

new 类名();
new Student();

一般实例化出来的对象需要用同类型的变量引用之,以便继续使用这个对象。

Student stu = new Student();
  • 所以每个类都是一种新的数据类型,也称为自定义的数据类型。凡是需要数据类型的地方,都可以使用类名。类都是引用数据类型。

    比如:变量类型 、 参数类型、返回值类型、数组的元素类型、成员变量的类型

1.3访问对象中的成员

对象中的成员变量、方法、内部类都可以访问.

对象中各种成员的访问语法是一样的,都是通过对象.去访问.

  • 成员变量

    对象.成员变量名
    
    stu.studentNo
    stu.studentName
    
  • 方法

    方法也都是通过对象.去调用

    对象.方法名([实参]);
    
    stu.sayHi("张三");
    stu.learn("Java程序设计");
    
public class Application{
	public static void main(String[] args){
		//实例化一个Student对象,并声明一个Student类型的变量去引用这个对象
		Student stu = new Student();
		//对象的使用无非就是访问对象中的成员(代码块这种成员不能访问)
		//1.访问对象中的成员变量
		stu.studentNo = 1001;
		stu.studentName = "张小马";
		stu.studentGender = "男";
		stu.studentClass = "软件1班";
		stu.studentAge = 18;
		System.out.println(stu.studentNo + "," + stu.studentName + "," + stu.studentGender + "," 
		  + stu.studentClass + "," + stu.studentAge);
		//2.调用对象中的方法
		stu.sayHi("王小六");
		stu.learn("Java程序设计");
		//3.内部类
		//stu.new StudentInner();
		System.out.println("=======================");
		Student stu2 = new Student();
		stu2.sayHi("李想");
		stu2.learn("Java高级API");
	}
}

1.3this

this代表一个对象:当前对象。

如果要在一个成员中,访问当前对象中的另一个成员,就需要使用this.

/**
 * 图书类
 */
public class Book{
	//成员变量
	long bookId;
	String bookName;
	String bookAuthor;
	String bookPress;
	int bookStatus;
	
	/**
	 * 打印当前图书对象的信息
	 */
	public void printInfo(){
		//this代表当前对象,可以用来访问当前对象中的其他成员
		System.out.println("*******************");
		System.out.println("图书编号:" + this.bookId);
		System.out.println("图书名称:" + this.bookName);
		System.out.println("图书作者:" + this.bookAuthor);
		System.out.println("图书出版社:" + this.bookPress);
		System.out.println("图书状态:" + this.bookStatus);
		System.out.println("*******************");
	}
}
  • 如果实在一个方法中使用this,那么 当前对象就是正在调用这个方法的对象。

  • 注意:this.可以省略,但是不建议省略。

this的特殊使用情况:一个构造方法中调用另一个构造方法,使用this,并且这个语句必须是第一条语句。

this(参数);
	//构造方法
	public Student(){
		//在一个构造中是可以调用另一个构造
		this(10000,"张飞","男","软件2班",25);//this代表要调用另一个构造,小括号中是实参
		System.out.println("这是Student的构造方法()");
		/*
		this.studentNo = 10000;
		this.studentName = "张飞";
		this.studentGender = "男";
		this.studentClass = "软件2班";
		this.studentAge = 25;*/
		
	}
	public Student(long studentNo, String studentName,String studentGender,String studentClass,int studentAge){
		System.out.println("这是Student的构造方法(long,String,String,String,int)");
		this.studentNo  = studentNo;
		this.studentName = studentName;
		this.studentGender = studentGender;
		this.studentClass = studentClass;
		this.studentAge = studentAge;
	}

2.对象的构造过程

2.1 构造过程

当使用new实例化一个对象时,底层虚拟机做了一下操作:

  • 第一:new代表分配内存空间。主要给对象的所有成员变量分配空间。
  • 第二:初始化成员变量
  • 第三:执行一次代码块
  • 第四:调用执行一次构造方法

2.2 构造方法

一种特殊的方法,特殊在两个地方:

  • 定义的语法特殊

    • 不能有返回类型
    • 方法 名必须就是类名
    public 类名(形参列表){
    	//方法体
    }
    
    public Student(){
    
    }
    
  • 调用特殊

    • 只能在new对象的时候自动调用,不能在其他地方调用。
    • 构造方法专门是用来构造对象的,一般里边的代码是做对象的初始化工作。
    new Student();
    

    更新下创建对象的语法:

    new 构造方法调用;
    
    new Student();
    new Student(实参);
    

一个类中可以定义多个构造方法,这些构造方法一定构成重载关系。

注意:一个类中如果没有显式的定义构造方法,那么系统会给类自动提供一个无参的构造方法。但是,如果自己显式定义了构造方法,那么系统的这个无参的就消失了,就调用不到了。所以建议,如果自己定义构造,无参的一定加上。

/**
 * 学生类
 */
public class Student {
	//类中的成员
	//1.成员变量(属性)
	long studentNo = 100;//学号
	String studentName = "张飞";//姓名
	String studentGender = "男";//性别
	String studentClass = "数据1班";//班级
	int studentAge = 18;//年龄
	
	//2.方法(行为)
	
	//构造方法
	public Student(){
		System.out.println("这是Student的构造方法()");
		this.studentNo = 10000;
		this.studentName = "张飞";
		this.studentGender = "男";
		this.studentClass = "软件2班";
		this.studentAge = 25;
	}
	public Student(long studentNo, String studentName,String studentGender,String studentClass,int studentAge){
		System.out.println("这是Student的构造方法(long,String,String,String,int)");
		this.studentNo  = studentNo;
		this.studentName = studentName;
		this.studentGender = studentGender;
		this.studentClass = studentClass;
		this.studentAge = studentAge;
	}
	
	/**
	 * 打招呼
	 * @param other 另一个学生
	 */
	public void sayHi(String other){
		System.out.println(this.studentName + "说:你好," + other);
	}
	/**
	 * 学习
	 * @param course 指定课程
	 */
	public void learn(String course){
		System.out.println(this.studentName + "今天学习了:" + course);
	}
	
	public void show(){
		System.out.println(this.studentNo + "," + this.studentName + "," + this.studentGender + "," 
		  + this.studentClass + "," + this.studentAge);
	}
	
	//3.代码块
	{
		//多行可执行的代码
		System.out.println("这是Student中的特殊成员:代码块");
		this.studentNo = 1000;
		this.studentName = "张翼德";
		this.studentGender = "男";
		this.studentClass = "软件1班";
		this.studentAge = 20;
	}
}
public class App{
	public static void main(String[] args){
		Student stu = new Student();
		stu.show();
		System.out.println("=================");
		Student stu2 = new Student(10001,"刘备","男","软件3班",40);
		stu2.show();
	}
}

2.3 对象的初始化

对象的初始化一般放在代码块中或者构造方法中。但是一般选择构造方法。

初始化工作中最简单的一种初始化就是给成员变量初始化。

  • 声明的同时进行成员变量的初始化

    这种只适合所有对象的成员变量的初始化值固定

  • 代码块中初始化

    代码块一般用来给对象进行初始化,所以一般也叫作 初始化块。

    初始化块中进行初始化,优点时 可以写代码逻辑,缺点:所有对象的初始化效果是一样的.

    注意:每new一个对象,代码块就会自动执行一次。

  • 构造方法中初始化

    构造方法初始化的优点:它是方法,可以带参数,所以可以定义多个,用参数区分;并且通过参数可以初始化不一样的效果。

  • 如果以上三种都没有给成员变量进行初始化,就是使用默认初始化。

    默认初始化值和数组中元素的默认初始化值一样。(0,0.0,false,null)

3.关于变量的作用域

变量分为局部变量和成员变量:

3.1 局部变量

  • 声明在代码块或者方法中的变量称为局部变量
  • 局部变量的作用域被局限在代码块或者方法的大括号中,就是局部范围。
  • 同作用域或者重叠 的作用域中不能声明同名的局部变量。会报错:变量重复声明

3.2 成员变量

  • 声明在类中的变量称为成员变量
  • 成员变量的作用域被局限在类中.
  • 同作用域中不能声明同名的成员变量。会报错:变量重复声明

但是重叠的作用域中可以声明同名的局部变量和成员变量。但是访问时,根据就近原则,局部变量较近,所以默认访问的就是局部变量。要访问到成员变量,必须加上this.也就是这种情况this.不能省略。

九、static

static用来修饰类中的成员。加了static修饰的成员属于类,叫做类成员或者静态成员。没有加static的成员属于对象,叫做实例成员或者对象成员。

类成员和实例成员的区别:

  • 定义时:类成员需要加上static。实例成员不需要加。

  • 访问时:类成员属于类,所以通过**类名.就可以访问。实例成员属于对象,所以必须通过对象.**才能访问。

  • 具体成员的区别:

    • 成员变量:实例成员变量属于对象,所以每个对象中都有一份。类成员变量属于类,因为类在全局只加载一次(一份),所以类成员变量在全局只有一份。

    • 方法:实例方法属于对象,所以不同对象调用方法时效果可能不同。类方法属于类,所以通过类名调用效果永远是一样的。

      成员变量和方法大部分是实例的。极少部分是静态的。

    • 代码块:实例代码块在每个对象创建的时候都执行一次;类代码块只在类加载的时候执行唯一的一次。

      一般只会用到静态代码块。

    • 内部类:只区分访问方式即可。实例内部类通过对象.访问。静态内部类通过类名.就可以访问。
      内部类一般也只会用到静态内部类。

public class StaticDemo{
	
	//实例成员
	int x;
	int y;
	
	public void showX(){
		System.out.println("x=" + this.x);
	}
	public void showY(){
		System.out.println("y=" + this.y);
	}
	
	{
		System.out.println("初始化代码块(实例)");
	}
	class Inner{}
	
	//类成员
	static int m;
	static int n;
	public static void showM(){
		System.out.println("m=" + StaticDemo.m);
	}
	public static void showN(){
		System.out.println("n=" + StaticDemo.n);
	}
	static{
		System.out.println("初始化代码块(静态/类)");
	}
	static class InnerStatic{}
}
public class App{
	public static void main(String[] args){
		//访问类成员
		StaticDemo.m = 1;
		StaticDemo.n = 2;
		StaticDemo.showM();
		StaticDemo.showN();
		//类代码块不能访问:只在类加载的时候执行一次
		StaticDemo.InnerStatic inner;
		
		System.out.println("=====================");
		//访问实例成员
		StaticDemo demo = new StaticDemo();
		demo.x = 10;
		demo.y = 20;
		demo.showX();
		demo.showY();
		//实例代码块不能访问:在每次实例化对象时候都会执行一次
		demo.new Inner();
		
		StaticDemo demo2 = new StaticDemo();
	}
}

注意:

  • 通过**对象.**也可以访问类成员。不要这么干。

  • 关于在一个成员中去访问当前类或者对象另一个成员:

    • 针对实例成员的话,用this. 而且this.可以省略

      一个实例成员中可以访问其他的类成员。

    • 针对类成员的话,还是用类名.,这是类名.可以省略

      但是类成员中不能直接访问当前类中的实例成员。因为类成员中不存在this.

static类成员的使用场景:

  • 如果某个数据或者对象在全局只存在一份,只是应该使用static静态成员变量去存储这个数据。

    例如:System.out System.in

  • 全局只有一个,或者说与对象无关的功能实现,应该使用static‘静态方法。

    最常见的是一些工具方法,比如各种数学运算Math类中全是静态的方法。

  • 全局要做的一些初始化操作,一般放在static静态初始化块中,就做一次。

    比如:一些全局上下文数据的初始化。比如数据库驱动的加载,比如服务的预热等等。

十、package和import

1.package

1.1定义包

package包:package语句可以用来给类设置包名。

作用:把程序中的大量类分包去管理。

语法:

package 包名;

注意:

  • package语句写在源文件的第一行

  • package语句用来给当前这个源文件中的所有类设置包名

  • 包名一般是点隔开的多级名称,每一级名称一般是标识符,而且小写

    package com.edu.demo;
    

    一般多级名称的起名原则是:公司域名反转.项目名.模块名

  • 包名在编码上的体现就是package语句。

    但是包在文件系统中的体现:需要把对应包的.java源文件(不必须)或者.class字节码文件(必须)放到每层包对应的文件夹中。Idea自动完成。

  • Idea中定义包有两种方式:

    • 第一种:创建类的时候就指定包

      new --> Java Class 输入:包名.类名

    • 第二种:先创建包

      new —> Package 输入:包名

1.2访问带包名的类

访问带包名的类:必须使用全类名:包名.类名 。 把类名叫做简单类名。

com.edu.demo.entity.Student stu = new com.edu.demo.entity.Student();

如果要简化类名的使用,就是使用简单类名:

  • 第一种情况:如果当前类和要访问的类的包名相同,可以省略包名.
  • 第二种情况:当前类和要访问的类不在一个包中,可以使用import导入

2.import

import语句用来导入一个类,当类导入以后,就可以直接使用简单类名。

import com.edu.demo.entity.Student;
import com.edu.demo.entity.*;

注意:

  • import语句必须写类外边
  • import导入时可以使用星号通配符
  • Idea中使用类时,直接输入简答类名,会自动import导入

注意:java类库中有个特殊的包:java.lang 这个包中的所有类会自动导入,不需要import,就可以使用简单类名。比如:System , String等等

十一、访问控制

访问控制:就是控制类或者其成员在哪里可以访问,在哪里不可以访问。

有三个访问控制修饰词可以用来设置访问权限。

这三个访问控制修饰词把访问权限分为了四种:

  • private:私有
  • 缺省:一个词都不加
  • protected:保护
  • public:公有、公开

这四种权限的访问范围是:

类内部同一个包中(类外部)在子类中(不在同一个包中)其他(不在同一个包中并且非子类)
private可以访问不可以不可以不可以
缺省可以可以不可以不可以
protected可以可以可以不可以
public可以可以可以可以

访问控制修饰词可以修饰类以及类中的成员:

  • 如果修饰类,只能使用public. 也就是类只有public的和缺省的。
  • 如果修饰类中的成员,三个修饰词都可以,也就是有四种权限。

原则:在不影响功能实现的情况下,权限越小越安全。

十二、面向对象的三大特征

1.封装

封装:就是把不需要外界了解的实现细节隐藏起来,然后给外界提供必要的访问接口。

现阶段面向对象的封装原则:

  • 把成员变量尽量私有化(private),然后如果那些成员变量需要外界访问,就提供必要的公开(public)的getter和setter方法,也就是如果要访问private私有的成员变量,直接调用对应的getter和setter方法即可。
  • 方法一般都是给外界访问的,也就是public。但是有些方法只服务于类中的其他方法,那么就可以private私有。
package com.edu.entity;

public class Student {
    //成员变量私有
    private long stuNo;
    private String stuName;
    private String stuClass;
    //提供public公开的getter和setter
    //每个成员变量都可以有自己的getter和setter方法
    //getter方法:获取成员变量的值
    public long getStuNo(){
        return this.stuNo;
    }
    //setter方法:给成员变量赋值
    public void setStuNo(long stuNo){
        this.stuNo = stuNo;
    }
    public String getStuName() {
        return this.stuName;
    }
    public void setStuName(String stuName) {
        this.stuName = stuName;
    }
    public String getStuClass() {
        return this.stuClass;
    }
    public void setStuClass(String stuClass) {
        this.stuClass = stuClass;
    }
    public Student() {
    }
    public Student(long stuNo, String stuName, String stuClass) {
        this.stuNo = stuNo;
        this.stuName = stuName;
        this.stuClass = stuClass;
    }
}

2.继承

2.1 继承

继承:如果一个类A包含了另一个类B中所有的成员,这时只需要让类A继承类B,就可以把类B中的成员都继承下来,也就是类A中就不需要再定义这些成员了。

所以:把被继承的类叫做父类/超类;把继承出来的类叫做子类/派生类。

继承的好处:

  • 代码复用
  • 有利于后期的扩展

扩展:继承其实准确来说,是在一个已有类的基础上扩展出来一个功能更强大的类。也就是继承以后子类中不仅包含了父类中所有的成员,还可以定义或者说扩展新的自己的成员。

一般父类比较抽象或者比较泛化;而子类比较具体。

比如:

  • 人类是父类,学生类就是从人类扩展出来的子类。
  • 动物类是父类,猫科动物是动物类的子类,狮子类是猫科动物类的子类
  • 手机类是父类,智能手机就是手机类的子类。
public class Person{}
public class Student extends Person{}

2.2 关于子类对象的构造

创建子类对象时,先自动创建一个父类对象,然后这个父类对象包含在子类对象中。

2.2.1 子类中的this和super问题
  • 子类中的this代表当前子类对象,所以this.既能访问子类扩展的成员,也能访问继承自父类的成员。this.可以省略。

    this可以用来在一个构造中调用当前类的另一个构造。必须是第一条语句。

  • 子类中的super代表当前子类对象中包含的那个父类对象。所以,super.只能访问继承自父类的成员。super.也可以省略。

    注意:有一种情况下,访问成员时,如果把this.和super.省略了,会有问题。

    当子类扩展的方法和父类中的方法相同(原型),这时this.访问的是子类中扩展的,super.访问的是继承自父类的。如果省略了,默认当作this.处理,也即是默认访问的是子类扩展的。如果非要访问继承自父类的,那么就不能省略super。

    super可以用来在子类构造中调用父类构造。super也必须是第一条语句。

2.2.2 子类中的构造方法问题

因为子类对象中包含了一个父类对象,所以就要求在构造子类对象时,先构造一个父类对象,也就是要求在子类构造方法的第一条语句必须先调用下父类构造。

如果子类构造中第一条不去调用父类构造,系统也会自动默认调用一下父类的无参构造。

如果要自己在子类构造的第一条语句调用父类构造,使用super:

    public Student(){
        //第一条语句调用父类构造,如果没有显式调用父类构造,默认自动调用父类的无参构造
        System.out.println("============Student()=============");
    }
    public Student(String name, int age, String gender, long stuNo, String stuClass){
        //第一条语句调用父类构造,显式调用父类的构造
        super(name, age, gender);
        this.stuNo = stuNo;
        this.stuClass = stuClass;
        System.out.println("============Student(String,int,String,long,String)=============");
    }

2.3 重写Override/Overwrite

重载:在一个类中,如果两个方法的方法名相同,形参列表不同,构成重载关系。

重写:在子类中,把继承自父类的某个方法重写重新实现一下。

重写的作用:因为有时父类中的方法实现不能满足子类的要求,这是子类就需要对这个方法进行重新实现。

所以:重新写的是方法的实现,方法的原型不变。

重写的要求:方法原型不变

  • 方法名不变

  • 方法形参列表不变

    注意:参数类型能自动类型转换也可以

  • 方法返回类型不变

    注意:返回类型能自动类型转换也可以

  • 方法的权限修饰词不变

    注意:权限可以更大

  • 方法抛出的异常类型不变

    注意:异常可以抛出更少,只能是子集

public void fun(String x) throws 多个异常类型{
}

练习:

  • 父类:手机类
    • 成员变量:品牌、型号
    • 方法:构造方法、打电话、发短信、show方法
  • 子类:智能手机类
    • 扩展的成员变量:内存大小、屏幕尺寸、颜色
    • 方法:扩展上网的方法,重写打电话、发短信和show方法
  • 测试:实例化子类对象,调用方法

2.4 上转型

java中的继承是一颗倒挂的树,父类在上,子类在下。

上转型:就是java可以自动把下边的子类对象转换为上边的父类类型。因为子类拥有父类的所有成员,所以把子类对象上转型为父类类型去使用,完全没有问题。

经常说:子类就是一种特殊的父类。 把学生Student当做Person人没问题,把智能手机当做手机使用没问题。

上转型的好处:

  • 上转型为父类类型,类型更通用。父类类型可以引用各种子类对象。
  • 上转型是多台的基础条件
package com.edu.entity;

public class UpConverterTest {

    public static void main(String[] args) {

        //把Student子类对象上转型为父类Person类型
        Person p = new Student("李四", 24, "男", 1002, "软件2班");
        //上转型以后调用方式时:调用的是子类中重写的那个
        p.show();

    }

}

编译时和运行时:

  • 编译时

    编译时检查类型,某个方法到底是否能调用,是在编译时决定的,所以能否调用看类型,不看对象。

  • 运行时

    调用方法的时候,具体选择调用哪个方法实在运行时决定的,而对象就是在运行时创建,也就是具体调用哪个方法,看的是对象,而不是类型。

上转型的缺点:

  • 因为编译时类型检查,通过类型确定一个成员是否能访问。就会造成上转型以后,子类扩展的功能(成员)都无法访问

下转型:

上转型以后,如果有需要转回到原来的子类类型,就叫做下转型。下转型只能强制类型转换。

package com.edu.entity;

public class UpConverterTest {

    public static void main(String[] args) {

        //把Student子类对象上转型为父类Person类型
        Person p = new Student("李四", 24, "男", 1002, "软件2班");
        //上转型以后调用方式时:调用的是子类中重写的那个
        p.show();
        //p.learn("");//编译时检查类型中有没有要调用的方法
        //p.stuNo = 1010;//编译时检查类型中有没有要访问的成员

        //解决上转型的坏处
        //下转型:先做判断
        if(p instanceof Student){
            Student s = (Student) p;
            s.learn("java高级程序设计");
        }else if(p instanceof Teacher){
            Teacher t = (Teacher) p;
            t.teach();
        }
    }
}

注意:为了不跑出类型转换一场,在下转型之前,先判断是否是目标类型的对象。

  • instanceof运算符

    对象  instanceof  类型
    

    结果是boolean类型,如果对象就是指定的类型,结果是true;否则结果是false

3.多态

多态:多态是一种现象,当父类类型的变量引用了不同子类类型的对象,在调用各种功能方法时,就会表现出不同子类重写的功能方法状态。引用的是哪个子类对象,表现得就是这种子类对象重写的状态。有多少种子类重写,就可以表现出多少种状态。

多态的基本条件:

  • 继承

    package com.edu.entity;
    
    /**
     * 人类:父类
     */
    public class Person {
    
        String name;
        int age;
        String gender;
    
        public Person(){
        }
        public Person(String name, int age, String gender){
            this.name = name;
            this.age = age;
            this.gender = gender;
        }
    
    
        public void show(){
            System.out.println("********信息*********");
            System.out.println("姓名:" + this.name);
            System.out.println("年龄:" + this.age);
            System.out.println("性别:" + this.gender);
        }
    
    
    }
    
    
    package com.edu.entity;
    
    /**
     * 学生类:继承Person类
     */
    public class Student extends Person {
    
        long stuNo;//学号
        String stuClass;//班级
    
    
        public Student(){
        }
        public Student(String name, int age, String gender, long stuNo, String stuClass){
            super(name, age, gender);
            this.stuNo = stuNo;
            this.stuClass = stuClass;
        }
    
    
    
    }
    
    
  • 重写

    
        public void show(){
            super.show();//在重写方法中可以使用super.调用父类中的对应方法
            System.out.println("学号:" + this.stuNo);
            System.out.println("班级:" + this.stuClass);
        }
    
  • 上转型

package com.edu.entity;

public class Application {

    public static void main(String[] args) {

        //Person p = new Student("张三",20,"男",1001,"软件1班");
        Person p = new Teacher("赵老师",40,"女","T001",10);
        p.show();
        p.eat("烤肉");
        p.sleep(6);

    }

}

十三、abstract和final

1.abstract

抽象,可以用来修饰类和方法,定义抽象类和抽象方法。

1.1 抽象方法

抽象方法:定义方法时,加上abstract关键修饰,就是抽象方法。

抽象方法不能有实现。

public abstract void fun();

意义:

父类一般比较抽象,子类比较具体。父类种有些方法是无法实现或者没必要实现的,这时方法就必须声明为抽象方法,就可以不实现。

也就是父类中不实现的方法,其实是把实现留给子类种重写时实现。

1.2 抽象类

抽象方法必须在抽象类中。

抽象方法:定义类时,加上abstract关键修饰,就是抽象类。

抽象类不能实例化对象。是用来扩展子类,然后实例化子类对象。

public abstract class Pet{
	public abstract void fun();
}

注意:子类种一般都会重写(也就是实现)父类中定义的抽象方法。如果不实现父类中的抽象方法,那么子类也必须声明为抽象类。

2.final

final可以修饰变量(局部变量和成员变量),方法,以及类。

  • 修饰变量,叫做常量。

    也就是初始化以后,不能再修改值。

    修饰成员变量,成员变量就必须在以下一个地方进行初始化,而且只能选一个地方:

    • 声明的同时初始化(static也一样)
    • 初始化代码块(static也一样)
    • 构造方法(只针对实例变量)
  • 修饰方法

    方法不能被子类重写

  • 修饰类

    类不能被继承(扩展)

final和abstract冲突,不能同时修饰类或者方法。

package com.edu;

public final  class Test {

    public final int X /*= 1*/;
    public static final int Y /*= 2*/;

    {
        //this.X = 10;
    }
    static{
        Y = 20;
    }
    public Test(){
        this.X = 100;
    }

    public final void fun(){}
}

十四、接口

面向接口开发和设计程序,有利于实现组件化,低耦合,可插拔。

1.接口

接口:跟类相似,也是 一种类型。接口中所有成员变量默认都是公开静态常量(public static final),所有的方法模式都是公开的抽象方法(public abstract)。

接口的定义和使用都跟类几乎一样。并且一般接口对应的是继承关系中的父类。重点是接口对应的是多态中上转型的父类。

接口的作用:接口中包含的都是抽象方法(没有实现),只有方法的原型,也就是说接口其实定义的是一种行为(方法)标准。然后在实现类中按照标准去实现这些行为方法。

2.接口的定义

接口 的定义和类相似,类 用的是class关键字。接口使用interface关键字。

public interface 接口名{
	//成员变量
	int PI = 3.14;//默认就是public static final
	//方法
	void fun();//默认就是public abstract
}
package com.edu.demo;

/**
 * 连接和执行sql语句的标准
 */
public interface ConnectionAndExecuteDatabase {

    /**
     * 连接数据库
     * @param url
     * @param username
     * @param password
     */
    void connect(String url, String username, String password);

    /**
     * 执行sql语句
     * @param sql
     * @return
     */
    String execute(String sql);

    /**
     * 关闭连接
     */
    void close();
}

3.接口的使用

接口的使用主要:

  • 接口是一种类型
  • 接口要给类去实现,就是实现接口中包含的抽象方法。
  • 所以:接口会大量使用在多态的情形中,代替父类。

接口和类的区别:

  • 定义时的关键字不一样:class interface

  • 接口中只能包含静态常量和抽象方法

  • 类之间继承以后,叫做父子关系。

    接口和类之间叫做实现关系:接口对应父类,实现类对应子类。

  • 类之间的继承只能单继承

    class Child extends 父类{}
    

    extends后边之后指定一个父类。

  • 接口和类之间的实现关系允许 多实现:一个类可以实现多个接口。

    class XxxImpl implements 接口1,接口2,...{}
    

    implements后边可以指定多个接口

  • 接口和接口允许多继承

    子接口可以继承下来父接口中的所有成员。

    interface 子接口  extends 父接口1,父接口2,...{}
    
  • 抽象类的限制,接口都有。不能实例化对象。接口比抽象类更抽象。

类实现接口:

public class 实现类的类名  implements 接口名{
	
}
package com.edu.demo;

/**
 * 针对于MySQL数据的接口实现
 */
public class MySQLImpl implements ConnectionAndExecuteDatabase {


    @Override
    public void connect(String url, String username, String password) {
        System.out.println("连接MYSQL数据库,地址是" +  url + ",用户名是:" + username + ",密码是:" + password);
    }

    @Override
    public String execute(String sql) {
        System.out.println("在MySQL数据上执行:" + sql);
        return "MYSQL执行结果";
    }

    @Override
    public void close() {
        System.out.println("关闭和MySQL数据库的连接");
    }
}

package com.edu.demo;

public class OracleImpl implements ConnectionAndExecuteDatabase{
    @Override
    public void connect(String url, String username, String password) {
        System.out.println("连接Oracle数据库,地址:" + url + ",用户名:" + username + ",密码:" + password);
    }

    @Override
    public String execute(String sql) {
        System.out.println("在Oracle数据上执行:" + sql);
        return "ORACLE执行结果";
    }

    @Override
    public void close() {
        System.out.println("关闭和Oracle数据库的连接");
    }
}

package com.edu.demo;

public class App {

    public static void main(String[] args) {
        //请连接数据库,并执行select * from student语句
        ConnectionAndExecuteDatabase ce = new OracleImpl();//可插拔
        ce.connect("jdbc:mysql://127.0.0.1:3306/db1", "root", "123456");
        ce.execute("select * from student");
        ce.close();
    }
}

接口是一种标准,先定义好标砖,再去按照标准进行不同的实现:

  • 低耦合

    与接口相关,与实现无关。降低了 和实现的耦合度。

  • 可插拔

    随意切换实现类 对象,都不影响代码的编写和运行。

十五、Java中的异常处理机制

异常:就是运行过程中发生的一种异于正常情况的状态。比如:下标越界异常、空指针异常、SQL异常、类型转换异常、解析异常、输入不匹配异常、无效参数异常、网络异常、找不到文件异常、读写异常等等。以及自定义的业务异常。

异常处理:如果异常发生以后,不进行捕捉处理,java程序就只在异常发生的地方直接终止运行,并打印出异常信息。为了保证程序不会异常终止,应该在异常可能发生的地方捕捉并处理异常。

1 捕捉处理异常

1.1 基本的try和catch

try{
	//有可能发生异常的代码块
}catch(异常类型 变量名){
	//捕捉到了异常,异常处理代码块
}
package com.edu.demo;

import java.util.Scanner;

public class ExceptionTest {

    public static void main(String[] args) {

        int[] arr = {10,100,40,58,90};
        Scanner input = new Scanner(System.in);
        System.out.print("请输入一个下标");
        int index = input.nextInt();
        try{
            int num = arr[index];
            System.out.println(index + "下标位上的数是:" + num);
        }catch(IndexOutOfBoundsException e){
            System.out.println("抓到异常了:" + e.getMessage());
        }

    }

}

1.2 一个try可以多个catch

一段代码块可能抛出多种类型的异常,这是就需要 多个catch去捕捉多种类型的异常。

package com.edu.demo;

import java.util.InputMismatchException;
import java.util.Scanner;

public class ExceptionTest {

    public static void main(String[] args) {

        int[] arr = {10,100,40,58,90};
        Scanner input = new Scanner(System.in);

        try{
            System.out.print("请输入一个下标:");
            int index = input.nextInt();
            int num = arr[index];
            System.out.println(index + "下标位上的数是:" + num);
        }catch(IndexOutOfBoundsException e){
            System.out.println("抓到下标越界异常了:" + e.getMessage());
        }catch(InputMismatchException e){
            System.out.println("抓到输入不匹配异常了:" + e.getMessage());
        }

    }

}

1.3 try最后还可以有finally代码块

finally代码块不管有没有抛出异常都会执行。

package com.edu.demo;

import java.util.InputMismatchException;
import java.util.Scanner;

public class ExceptionTest {

    public static void main(String[] args) {

        int[] arr = {10,100,40,58,90};

        Scanner input = null;
        try{
            input = new Scanner(System.in);//这行会打开输入流资源
            System.out.print("请输入一个下标:");
            int index = input.nextInt();
            int num = arr[index];
            System.out.println(index + "下标位上的数是:" + num);
        }catch(IndexOutOfBoundsException e){
            System.out.println("抓到下标越界异常了:" + e.getMessage());
        }catch(InputMismatchException e){
            System.out.println("抓到输入不匹配异常了:" + e.getMessage());
        }finally {
            System.out.println("finally代码块一定执行!!!");
            //一般做:在try中打开的资源,不管有没有抛出异常,在trycatch快结束的时候都应该关闭或者回收资源
            if(input != null){
                input.close();
            }
        }
    }

}

1.4 抛出异常以后的执行流程问题

当一行代码抛出异常以后,先看当期位置能不能捕捉处理,如果能直接catch、finally继续往下;如果不能捕捉处理,执行下当前位置的finally,当前方法直接return返回到调用的地方,然后看调用的地方能不能捕捉处理,按照这个过程一直根据方法的调用往上找,直到找到能捕捉处理异常的地方。如果找到main中还不能补助处理,那就程序终止。

2 异常类型

异常本质就是对象,所以肯定类型。

所有的异常都必须继承Throwable类。

Throwable

  • Exception

    Exception下边的子类一般是可处理的异常。

    Exception又分为两种:

    • RuntimeException

      运行时异常,他自己或者她的子类,这些异常可以捕捉处理,但是不建议捕捉处理,应该在异常抛出的地方通过条件判断去避免这种异常方法。

      比如:下标越界、空指针等等

    • 其他:也叫作受检异常

      比如 SQL异常等等

  • Error

    Error下边的子类一般是无法处理的异常,也叫做眼中错误异常。比如虚拟机异常。这种异常不要捕捉,不要处理,就让程序直接终止。

3 自定义异常

系统定义好的异常类型,叫做系统异常。比如下标越界、空指针等等。系统异常会在发生的时候自动抛出来。

自定义异常是与开发的项目业务相关的异常,需要自己定义。自定义异常不仅需要自己定义,而且在发生的时候,需要自己抛出。

自定义异常一般不建议继承Throwable,而选择继承它的子类Exception。

public ArrayOverflowException extends Exception{
    
    //定义下带参构造,初始化继承自父类的成员message
    public ArrayOverflowException(){}
    public ArrayOverflowException(String message){
        super(messsage);
    }
    
}

4.异常的抛出和声明

4.1 异常的抛出throw

throw 异常对象;
throw new Exception();

4.2 异常的声明throws

public void fun() throws 异常类型1,异常类型2 {}

十六、Java系统类库

1.按照包分类:

  • java.lang

    这个包中是最基础的类,System、String (StringBuilder\StringBuffer)、8个基本数据类型的包装类、Math、Thread多线程等等

  • java.util

    这个包中是一些工具类,Scanner 、 Random、Date/Calendar 、Arrays、集合框架相关的借口和类、Timer定时器等等

  • java.awt和javax.swing

    这两个包中都是GUI图形化界面变成相关的接口和类

  • java.sql

    数据库变成相关的接口和类

  • java.io和java.nio

    这两个包中都是输入输出相关的接口和类

  • java.net

    网络编程相关的接口和类

  • org.w3c或者org.xml

    这是w3c相关的接口和类。解析生成xml

2.八个基本数据类型的包装类

int short long byte double float char boolean

Integer Short Long Byte Double Float Character Boolean

Number类是前六个的父类。

一般基本数据类型和引用数据类型可以自动转换,java中把这种自动转换称为自动装箱和自动拆箱。

package com.edu;

public class IntegerDemo {


    public static void main(String[] args) {

        //Integer
        int a = 1;
        Integer ia = new Integer(1);
        //自动装箱  int  --->   Integer
        Integer ib = 2;
        //自动拆箱   Integer  --->   int
        int b = new Integer(2);

        //字符串转换为对应的基本数据类型
        //  "12"  --->    12
        int num = Integer.parseInt("12");
        //"3.14"    3.14
        double dnum = Double.parseDouble("3.14");
        //  12  ---> "12"
        String str = Integer.toString(12);
        String str2 = 12 + "";
        //上转型
        Number n = new Integer();
    }
}

3.String字符串

String是java中基本字符串类型,java还有两种字符串类,StringBuilder,StringBuffer

这三个都实现了同一个接口,字符序列接口 CharSequence。

package com.edu;

public class StringDemo {

    public static void main(String[] args) {
        //String :所有new出来的对象都在堆区
        String str = new String("Hello");
        String str2 = new String("Hello");
        //引用数据类型判断相等,可以使用==,也可以调用对象中的equals方法
        //如果是==。判断的是 是否是同一个对象
        System.out.println(str == str2);//false
        //equals是一个方法,它到底怎么判断相等,要看方法的代码怎么实现的
        //String类中的equals方法的实现是:判断两个字符串对象中的字符序列是否一样
        System.out.println(str.equals(str2));//true
        //String比较特殊,String可以引用常量池中的字符串常量, 同一个常量对象,在常量池中只存在一份
        String str3 = "Hello";
        String str4 = "Hello";
        System.out.println(str == str3);//false
        System.out.println(str.equals(str3));//true
        System.out.println(str3 == str4);//true
        System.out.println(str3.equals(str4));//true

        //String中的方法:字符串处理方法,比如字符串长度,字符串大写转换,字符串拆分,字符串替换,字符串截取,字符串中某个字符的获取等等
        String filename = "HelloWorld.java";
        System.out.println("charAt(5) : " + filename.charAt(5) );
        System.out.println("长度:" + filename.length());
        System.out.println("是否是java源文件:" + filename.endsWith(".java"));
        System.out.println("截取后缀:" + filename.substring(filename.lastIndexOf(".")));
        //String字符串不可变,String中对字符串进行变化操作的方法。都是生成一个新的字符串返回,源字符串没变
        String newFIlename = filename.toLowerCase();//转全小写
        System.out.println(newFIlename);
    }

}

4.Date日期

java.util.Date 和 java.util.Calendar 和 DateFormat

package com.edu;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Scanner;

public class DateDemo {

    public static void main(String[] args) {

        Date currentDate = new Date();//不带参的构造,初始化的是当前系统时间
        Date birthday = new Date(90,0,15);//参数中年从1900开始算,月从0开始算
        Date orderTime = new Date(123,0,15,8,10,10);

        System.out.println(currentDate);
        System.out.println(birthday);
        System.out.println(orderTime);

        long currentTime = System.currentTimeMillis();//时间戳(毫秒数)
        long orderTime2 = orderTime.getTime(); // Date   --->   long
        Date orderTime3 = new Date(orderTime2);// long   --->   Date

        Calendar calendar = Calendar.getInstance();//getInstance方法会实例化一个Calendar对象,并返回。初始化的也是当前系统时间
        System.out.println(calendar);
        //Calendar中的方法
        Date cd = calendar.getTime();// Calendar  --->  Date
        long ct = calendar.getTimeInMillis();//  Calendar  --->  long
        calendar.setTime(new Date());// Date  --->  Calendar
        calendar.setTimeInMillis(orderTime2);// long  --->  Calendar
        //Calendar中有大量的get和set方法
        calendar.set(Calendar.YEAR, 2022 );
        calendar.set(Calendar.MONTH, 3 );
        calendar.set(Calendar.DATE, 3 );
        calendar.set(2020,0,1);
        calendar.set(2020,0,1,8,10,0);
        System.out.println(calendar.get(Calendar.YEAR));
        System.out.println(calendar.get(Calendar.MONTH)+1);
        System.out.println(calendar.get(Calendar.DATE));

        //日期格式
        //如果日期按照某个格式组织为一个字符串,这是需要转换为Date类型
        Scanner input = new Scanner(System.in);
        System.out.print("请输入日期时间(yyyy-MM-dd HH:mm:ss):");
        String dateStr = input.nextLine();
        //按照格式解析日期时间字符串
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            Date date = format.parse(dateStr);//String  --->   Date
            String str = format.format(date);//Date  --->  String
            System.out.println(str);
        } catch (ParseException e) {
            e.printStackTrace();
            System.out.println("格式不正确");
        }


    }

}

5.Object

Object也是类库中定义的类,这个类是所有类的父类。如果定义类时,没有指定父类,默认以Object作为父类。
根据上转型的概念,Object类型的变量可以引用任何对象。Object可以实现超级类型通用。
根据继承的概念,Object类中的成员会被所有类继承下去。
Object中的成员:

  • toString: toString方法是把对象相关信息拼接为一个字符串返回。

    Object类中已经实现了toString,拼接出来的字符串是: 对象全类名@对象地址。

    一般都会重写toString方法,以方便输出对象信息。

  • equals: equals是一个用来判断两个对象是否相等的方法
    == 和 equals的区别:
    当使用==判断两个是否相等,其实判断的是是否是同一个对象。
    Object已经实现了equals方法,但是他的实现也是判断是否是同一个对象。一般都会重写equals方法。

package com.edu;

public class Student {

    String stuno;
    String stuname;
    public Student(){}
    public Student(String stuno, String stuname) {
        this.stuno = stuno;
        this.stuname = stuname;
    }

    //重写父类Object的toString
    @Override
    public String toString() {
       return "学号:" + this.stuno + ",姓名:" + this.stuname;
    }

    public boolean equals(Object other){
        if(this == other){
            return true;
        }
        if(other == null){
            return false;
        }
        //学号和姓名相同就认为两个对象相等
        if(other instanceof Student){
            Student that = (Student) other;
            if(this.stuno.equals(that.stuno) && this.stuname.equals(that.stuname)){
                return true;
            }
        }

        return false;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值