java语法基础

目录

标识符

关键字

字面值

变量

数据类型

计算机在任何情况下都只能识别二进制。简单点,只认识 0 和 1

补码

数据类型之间的相互转换

运算符

控制语句

if 语句  --> 选择结构

键盘上获取数据Scanner

switch  --> 选择结构

for 语句  -->  循环结构

foreach(也叫作 增强for循环)

break语句

continue语句

while 语句  -->  循环结构

do...while 循环

方法

main方法

return关键字

方法内存执行分析

方法重载

方法递归



标识符

  • 什么是标识符?

        在Java源程序中,可以由程序员自己命名的“单词”都是标识符。

  • 标识符的命名规则?

       规则:如果不按照这个规则来命名的话,编译器会报错,这属于语法。

       - 只能有“数字(0~9)、字母、下划线(_)、美元符号($)”组成,不能含有其他的符号

       - 不能以数字开头、严格区分大小写、关键字不能做标识符

       -  理论上无长度限制,但是最好不要太长

  • 标识符的命名规范?

        规范:属于一种默认遵守的约定,不按照规范来,编译也不会报错

        - 最好是见名知意

public class UserService{
    public void login(String username, String password){

	}
}

        - 遵循驼峰命名方式

                UserServer

                MyUser

        - 类名、接口名:首字母大写,后面的每一个单词首字母大写

        - 变量名、方法名:首字母小写,后面每一个单词首字母大写。

        - 常量:每一个字母都大写

  • 标识符可以标记什么元素?

        类名、方法名、变量名、接口名、常量名。。。。。。

public class MyFirstTest{ //MyFirstTest是一个类名,名字可以修改

	//main是一个方法名
	public static void main(String[] args){ //args是一个变量名
		
	}
	
	//doSome就是方法名
	public static void doSome(){
		int i = 20;//i就是变量名
	}
}

关键字

classextendsimplementsinterfaceimport
doifelseforreturn
packagebreakcasecontinuedefault
switchwhilefalsetruenull
booleanbytecharshortint
longfloatdoubletrycatch
throwthrowsfinallyabstractfianl
nativeprivateprotectedpublicstatic
synchronizedtransientvolatileinstanceofnew
supervoidassertenumgoto
const

字面值

  • 什么是字面值?字面值包括什么?

        字面值就是数据。

        - 10、100                        属于整数型字面值

        - 3.14                               属于浮点型字面值

        - “abc”、"大家好"               属于字符串型字面值

        - true、false                       属于布尔型字面值

        - 'A'、'人'                            属于字符型字面值

  • 字面值做什么的?

        字面值是Java源程序的组成部分之一,标志符合关键字,它们都是java源程序的组成部分

  • 使用字面值注意什么?

        - java语言当中所有的字符串型字面值必须使用双引号括起来,双引号是半角
        - java语言当中所有的字符型字面值必须使用单引号括起来,单引号是半角

public class ConstTest{
	
	public static void main(String[] args){
		
		System.out.println("abcd");
		System.out.println("你好");
		
		//10是一个字面值,是一个整数型数值,那么既然是数据存储在内存当中,必会占用一定的内存空间。
		System.out.println(100);
		System.out.println(3.14);
		
		System.out.println("3.1");
		System.out.println('A');
		
		System.out.println(true);
		//编译报错,因为单引号中只能存放单个字符,属于字符型字面值
		//System.out.println('ABC');
	}
}

变量

  • 什么是变量?变量的要求?

        - 变量本质上来说是内存中的一块空间。

        - 这块空间 --> 变量包括三部分:数据类型、名称、字面值【数据】

        - 变量是内存中存储数据的最基本的单元。

        - 变量中存储的具体的"数据"必须和变量的"数据类型"一致,当不一致的时候编译报错。

  • 数据类型的作用?

        - 不同的数据有不同的类型,不同的数据类型底层会分配不同的大小的空间。

        - 数据类型是指导程序在运行阶段应该分配多大的内存空间。

  • 声明/定义变量的语法格式?

        数据类型 变量名;

int i;
double num;
  • 变量的声明和赋值

        - 变量在一行上可以声明多个

int a,b,c;

        数据类型 变量名 = 字面值;

int i;
i = 2;

        - 要求:字面值的数据类型必须和变量的数据类型一致。

        = 等号是一个运算符,也叫赋值运算符,赋值运算符先运算等号右边的表达式,表达式执行结束之后的结果赋值给左边变量。

        - 声明和赋值可以放在一起完成

int i = 2;

        - 变量赋值之后,可以重新赋值,变量的值可变化

int i = 10;
System.out.println(i);  //10
i = 20;
System.out.println(i);  //20

        - java中的变量必须先声明,再赋值,才能访问。

public class Test{

	public static void main(String[] args){
	
		int i;  //声明一个int类型的变量,起名i
		
		//System.out.println(i);	//编译报错:变量i并未初始化
	}
}

        int i; 程序执行到这里,内存空间并没有开辟出来,变量i并没有初始化。所以没有赋值之前是无法访问的。

  • 有了变量的概念之后,内存空间得到了重复度额使用

  • 访问变量包括两种访问形式

        - 第一种:读取变量中保存的具体的数据  --> get/获取

        - 第二种:修改变量中保存的具体的数据  --> set/设置

i = 20;   //set
System.out.println(i);  //get
  • 变量的作用域

        - 变量的作用域,其实描述的就是变量的有效范围。
          在什么范围之内是可以被访问的,只是出了这个范围该变量就无法访问了。

public class Test{

	static int k = 90; //注意:在这里的static不能去掉

	public static void main(String[] args){
		//变量i的作用域是main方法
		//在整个main方法当中是有效的,可见的,可以访问的
		int i = 100;
		System.out.println(i);   //可以
		System.out.println(k);   //可以
		
		//以下会编写一个for循环语句
		for(int a = 0; a < 10; a++){  //a变量的作用域是整个for循环,for循环结束之后,a变量的内存就释放了
		}
		//System.out.println(a); //这里无法访问a变量
		
		int j;  //作用域是main方法
		for(j = 0; j < 10; j++){
		}
		System.out.println(j);  //访问的是main方法中的j变量
	}
	
	public static void doSome(){
		//System.out.println(i); //这里无法访问main方法当中的变量i,已经出了i变量的作用域。
		System.out.println(k); //可以访问
	}
}

总之,记住一句话:出了大括号就没关系了

  • 代码执行顺序

        - 在方法体当中的java代码,是遵守自上而下的顺序一次执行的,逐行执行。

                第一行代码;

                第二行代码;

                第三行;

          特点:第二行的代码必须完整的结束之后,第三行程序才能执行。

        - 在同一个"作用域"当中,变量名不能重名,但是变量可以重复赋值。

public void test(){
		
	int i = 100;
	System.out.println(i);  // 100

    //int i = 30;  // 会报错,变量名不能重名
    i = 200;        // 变量可以重复赋值。
	System.out.println(i);  // 200
}
  • 变量的分类

根据变量声明的位置来分类

        - 局部变量 : 在方法体当中声明的变量叫做局部变量

        - 成员变量 : 在方法体外【类体之内】声明的变量叫做成员变量

在不同的作用域中,变量名是可以相同的。在同一个作用域中,变量名不能重名。

public class Test{

	int k = 200;  //成员变量
	
	//主方法:入口
	public static void main(String[] args){
		
		int i = 10; //i变量就是局部变量
		System.out.println(i);  //java遵循"就近原则"
	}
	
	int i = 100;  //声明 成员变量
	//类体中不能直接编写java语句【除声明变量之外】
	//System.out.println(i);
	
	//doSome方法
	public static void doSome(){
		int i = 90;  //局部变量
	}
}

数据类型

  • 数据类型的作用是什么?

        - 程序当中有很多数据,每个数据都是有相关类型的,不同数据类型的数据占用空间大小不同。数据类型的作用是指导JVM在运行程序的时候给该数据分配多大的的内存空间。

  • java中的数据类型包括两种:基本数据类型、引用数据类型

        - 基本数据类型包括四大类(八小类):

                第一类:整数型 --> byte, short, int, long
                第二类:浮点型 --> float, double
                第三类:布尔型 --> boolean
                第四类:字符型 --> char

        - 引用数据类型:

                例如:接口、类、数组等等

        - 注意:字符串"abc"不属于基本数据类型,属于"引用数据类型",字符属于基本数据类型
                - 字符串使用双引号 "abc"
                - 字符使用单引号   'a'

  • 各种数据类型的信息

  • 计算机在任何情况下都只能识别二进制。简单点,只认识 0 和 1

  • 什么是二进制?

        - 数据的一种表示形式。十进制表示满十进一的原则。二进制表示满二进一原则。

  • 字节(byte)

        1 Byte = 8 bit 【1个字节 = 8个比特位】 1个比特位表示一个二进制位:1/0
        1 KB = 1024 Byte
        1 MB = 1024 KB
        1 GB = 1024 MB
        1 TB = 1024 GB

  • 字符编码

为了让计算机可以表示现实世界当中的文字,我们需要进行人为的干涉,需要人负责提前制定好"文字"和"二进制"之间的对照关系。这种对照转换关系被称为:字符编码。

计算机最初只支持英文,最先出现的字符编码是:ASCII码
                'a' --> 97【01100001】
                'A' --> 65
                '0' --> 48
                
                'a' --(按照ASCII解码)--> 01100001
                01100001 --(按照ASCII编码)--> 'a'
编码和解码的时候采用同一套字典/对照表,不会出现乱码。
当解码和编码的时候采用的不是同一套对照表,会出现乱码问题。

随着计算机的发展,后来出现了很多种编码方式,如:ISO-8859-1(latin-1)、GB2312、GBK、 GB18030、big5、UTF-8、UTF-16、UTF-32等等

现在在实际开发中,一般使用UTF-8编码方式较多。【统一编码方式】

  • 整数型

        - byte, short, int, long

        - java语言当中的"整数型字面值"被默认当做int类型来处理。要让这个"整数型字面值"被当做long类型来处理的话,需要在"整数型字面值"后面加上l/L【建议使用大写的L】。

        - java语言当中的整数型字面值有三种表达方式:
                第一种方式:十进制【是一种缺省默认值的方式】
                第二种方式:八进制【在编写八进制整数型字面值的时候需要以0开始】
                第三种方式:十六进制【在编写十六进制整数型字面值的时候需要以0x开始】

int a = 10;
int b = 010;   //整数型字面值以0开头的,后面那一串数字就是八进制形式
int c = 0x10;  //整数型字面值以0x开头的,后面那一串数字就是十六进制形式
		
System.out.println(a);      //10 
System.out.println(b);      //8
System.out.println(c);      //16
System.out.println(a + b + c);  //34

        - 当一个整数字面值没有超出byte, short, char的取值范围,这个字面值可以直接赋值给byte, short, char类型的变量。这种机制SUN允许了,目的是为了方便程序员的编程。

//这说明:在java语言当中,当一个整数型字面值没有超过byte, short, char类型取值范围的话,
//该字面值可以直接赋值给byte, short, char类型的变量。
byte a1 = 50;   //可以		
byte b1 = 127;  //可以
char cc = 65535; // 可以
short s = 32767; // 可以
  • 补码

(一)补码: 整型以补码形式存放
            (1)一个正数的补码是此数的二进制形式
            (2)一个负数的补码,先求其绝对值的补码,然后该补码所有位取反(0、1交换),所得之数最后加 1
            (3)0 的补码, 所有位全是 0
          注: 在存放整型的存储单元中最左边一位是用来表示符号的。(正整数最左边一位是 0, 负整数最左边一位是 1)
                  8位二进制(一个字节)补码所代表的整数:
         二进制                                  十进制
      0000 0000    -------------------------      0
      0000 0001    -------------------------      1
           ......                                      .....
      0000 1111    -------------------------    127       ==   2^(8-1)-1     最大正数
      1000 0000    -------------------------   -128      ==   -2^(8-1)       最小负数
      1000 0001    -------------------------   -127      ==   -(2^(8-1)-1)
      1111 1111    -------------------------     -1

总结:
    二进制补码 n 位所代表的整数范围: -2^(n-1) ~ 2^(n-1)-1

//原始数据:00000000 00000000 00000000 00000000 10000000 00000000 00000000 00000000
//强转后的数据:10000000 00000000 00000000 00000000
//10000000 00000000 00000000 00000000目前存储在计算机内部,计算机存储数据都是采用补码的形式存储的。所以10000000 00000000 00000000 00000000现在是一个补码形式
//将以上的补码转换到原码就是最终的结果
long k = 2147483648L;
int e = (int)k;
System.out.println(e);  //损失精度严重,结果是负数【-2147483648】
//原始数据:00000000 00000000 00000000 11000110
//强制类型转换之后:11000110
//11000110现在在计算机当中存储,它是一个补码,将补码转换成原码就是该数字:
//11000110 - 1 --> 11000101
//00111010 【2 + 8 + 16 + 32】 --> 58
//-58
byte q = (byte)198;
System.out.println(q);  //-58

计算机二进制有三种表示形式:
                    原码、反码、补码
  计算机在任何情况下底层表示和存储数据的时候采用了补码形式。
                正数的补码:和原码相同
                负数的补码:负数的绝对值对应的二进制所有二进制位取反,再加1
            补码:10000000
            原码计算过程:
                    * 10000000 - 1 --> 01111111
                    * 10000000 --> 128
                    * -128

//编译报错,128这个int类型的字面值已经超过byte类型的取值范围,不能直接赋值给byte类型的变量
//byte c1 = 128; 	
//纠正错误,需要使用强制类型转换符,但是一定会损失精度
//原始数据:00000000 00000000 00000000 10000000
//强转后的数据:10000000【这是存储在计算机内部的,这是一个补码】
byte c1 = (byte)128;
System.out.println(c1);     //-128
  • 浮点型

        - float    单精度【4个字节】
        - double   双精度【8个字节,精度较高】

//3.0是double类型的字面值,d是double类型的变量
//不存在类型的转换
double d = 3.0;
System.out.println(d);

       double的精度太低【相对来说的】,不适合做财务软件。财务涉及到钱的问题,要求精度较高,所以SUN在基本SE类库当中为程序员准备了精度更高的类型,只不过这种类型是一种引用数据类型,不属于基本数据类型,它是:java.math.BigDecimal

        - 在java语言当中,所有的浮点型字面值【如:3.0】,默认被当作double类型来处理,要想该字面值当做float类型来处理,需要在字面值后面添加F/f

//5.1是double类型的字面值,f是float类型的变量
//大容量转换到小容量需要加强制类型转换符,所以以下程序编译错误。
//float f = 5.1;  // 编译报错

//解决方案
//float f = (float)5.1; //第一种方式
float f = 5.1F;  //第二种方式

        - 注意:
         double和float在计算内部二进制存储的时候存储的都是近似值。在现实世界当中有一些数字是无限循环的,例如:3.333333333....
         计算机的资源是有限的,用有限的资源存储无限的数据只能存储近似值。

  • 字符类型

        - 普通的字符

//普通字符		
char c = 'a';  //定义一个char类型的变量,起名c,同时赋值字符'a'
System.out.println(c);

//一个中文占用2个字节,char类型正好是2个字节,所以java中的char类型变量可以存储一个中文字符
char x = '国';
System.out.println(x);

//ab是字符串不能使用单引号括起来
//char y = 'ab';  //编译错误

//"a"是字符串类型,k变量是char类型
//char k = "a"; //类型不兼容,编译出错

        - 转义字符 --> \(反斜杠)

                转义字符出现在特殊字符之前,会将特殊字符转换成普通字符。

                    \n  -->  换行符
                    \t   -->  制表符
                    \'   -->  普通的单引号
                    \\   -->  普通的反斜杠
                    \"   -->  普通的双引号

                   '\u4e2d'  --> '中'    【反斜杠 + Unicode编码】

//普通的n字符
char c1 = 'n';
System.out.println(c1);

//编译成功,说明以下不是一个字符串,而是"一个"字符
//反斜杠在java语言当中具有转移功能
char c2 = '\n';  //这是一个"换行符",属于char类型的数据
System.out.println(c2);

char n = '\u4e2d';  //'中'对应的Unicode编码是 4e2d
System.out.println(n);

        - char类型默认值

char q = '\u0000';  //char类型的默认值
System.out.println(q);  //输出: 空
System.out.println(q + 1);  //输出:1
  • 布尔类型

        - 在java语言当中Boolean类型只有两个值:true、false,没有其它值。不像C语言当中,0和1可以表示假和真。在底层存储的时候,Boolean类型占用1个字节,因为实际存储的时候false底层是0,true底层是1。布尔类型在实际开发当中非常重要,经常使用在逻辑运算和条件控制语句当中。

//boolean flag = 1; //编译错误:不兼容的类型
		
//boolean loginSuccess = false;
boolean loginSuccess = true;
		
//if语句
if(loginSuccess){
	System.out.println("登陆成功!");
}else{
	System.out.println("对不起,登录失败!");
}
  • 数据类型之间的相互转换

        * 八种基本数据类型当中除布尔类型之外剩下的7种类型之间都可以互相转换
        
        * 小容量向大容量转换,称为自动类型转换,容量从小到大排序:
                byte < short(char) < int < long < float < double
            注意:
                任何浮点类型不管占用多少个字节,都比整数型容量大。
                char和short可表示的种类数量相同,但是char可以取更大的正整数。
                
        * 大容量转换成小容量,叫做强制类型转换,需要加强制类型转换符,程序才能编译通过,但是在运行阶段可能会损失精度,所以谨慎使用。
        * 当整数字面值没有超出byte, short, char的取值范围,可以直接赋值给byte, short, char类型的变量。
        * byte, short, char混合运算的时候,各自先转换成int类型再做运算。
        * 多种数据类型混合运算,先转换成容量最大的那种类型再做运算。

        * 默认就是int类型

byte b = 3;  //可以编译通过,3没有超过byte类型取值范围
			
int i = 10;
byte b = i / 3;  //编译报错,编译器只检测语法,不会"运算" i / 3

        - 不能超过数据类型的范围,否则编译会报错

//byte a = 1000;  //编译出错,1000超出了byte的范围

byte a = 20;  //正确,因为20没有超过byte的范围,所以赋值

short b = 1000;  //正确,因为数值1000没有超过short类型的范围,所以赋值

        - 小容量的类型 -(转换)-> 大容量的类型

int c = 1000;
long d = c;  //可以,自动转换

         - 大容量的类型 -(转换)-> 小容量的类型(容易出现精度丢失问题)

long d = 1000;   
//int e = d;  //编译错误,出现精度丢失问题,大容量的类型-->小容量的类型会出现的问题
//将long类型强制转换成int类型
int e = (int)d;  //因为值1000,没有超出int范围,所以转换是正确的

        - java中的运算会转换成最大类型

//因为java中的运算会转换成最大类型
//而10和3默认为int,所以运算后的最大类型也是int
//所以是正确的
int f = 10/3; 
		
long g = 10; //声明10为long类型
		
//出现错误,多个数值在运算过程中,会转换成容量最大的类型
//以下实例最大的类型为long,而h为int,所以就会出现大类型(long)到小类型(int)的转换,将会出现精度丢失问题。
//int h = g/3; //编译错误
		
//可以强制转换,因为运算结果没有超过int范围
//int h = (int)g/3; //可以
		
//可以采用long类型来接收运算结果
//long h = g/3; //可以

        - 出现精度损失问题,也有可能是优先级的问题

long g = 10;

//将g转换成int,然后又将int类型的g转换成byte,最后byte类型的g和3运算,
//那么它的运算结果类型就是int,所以int赋值给byte就出现精度损失问题
//byte h = (byte)(int)g/3;  //错误
		
//byte h = (byte)(int)(g/3);  //可以
		
//不能转换,因为优先级的问题
//byte h = (byte)g/3;     //编译错误
		
//可以转换,因为运算结果没有超出byte范围
//byte h = (byte)(g/3);     //可以

//可以转换,因为运算结果没有超出short范围
//short h = (short)(g/3);     //可以

        - 关于数据类型的运算

​short i = 10;
byte j = 5;
		
//错误,short和byte运算,首先会转换成int再运算,所以运算结果为int,int赋值给short就会出现精度丢失问题
//short k = i + j;   //编译错误
		
//可以将运算结果强制转换为short类型
//short k = (short)(i + j);   //可以
		
//因为运算结果为int,所以可以采用int类型接收
int k = i + j;
		
char l = 'a';
System.out.println( (byte)l );   //输出:97,也就是a的ASCII值
		
int m = l + 100;
System.out.println(m);  //输出:197,取得a的ASCII码值,然后与100进行相加运算
		
double dd = 10 / 3;
System.out.println(dd);     //输出:3.0
		
dd = 10.0 / 3;
System.out.println(dd);   //输出:3.3333333333333335

运算符

  • 算术运算符

        - 一个表达式当中有多个运算符,运算符有优先级,不确定的加小括号,优先级得到提升。【没有必要去专门记忆运算符的优先级。】

                +    求和
                -    相减
                *    乘积
                /    商
                %    取余数【取模】

int i = 10;
int j = 3;
System.out.println( i + j );  //13
System.out.println( i - j );  //7
System.out.println( i * j );  //30
System.out.println( i / j );  //3
System.out.println( i % j );  //1

                ++   自加1  【单目运算符】
                --   自减1    【单目运算符】

        ++运算符可以出现在变量前,也可以出现在变量后,无论是变量前还是变量后只要++运算符结束,该变量中的值一定会自加1

//++ 出现在变量后,规则:先做赋值运算,再对变量中保存的值进行自加1。
int a = 100;
int b = a++;
System.out.println(a);  //101
System.out.println(b);  //100
		
//++ 出现在变量前,规则:先进行自加1运算。然后再进行赋值操作。
int m = 20;
int n = ++m;
System.out.println(m);  //21
System.out.println(n);  //21

int e = 100;
System.out.println( e++ ); //100
System.out.println( e );   //101

int s = 100;
System.out.println( ++s );  //101
System.out.println( s );    //101
  • 关系运算符

        >      大于
        >=     大于等于
        <      小于
        <=     小于等于
        ==     等于   【=是赋值运算符】
        !=     不等于        

【关系运算符的运算结果一定是布尔类型:true/false】

关系运算符的运算运算原理:

        int a = 10;
        int b = 10;
        a > b 比较的时候,比较的是a保存的10这个值和b保存的10这个值之间的大小比较。
        a == b 也是如此。

int a = 10;
int b = 20;
System.out.println(a > b);   //true
System.out.println(a >= b);  //true
System.out.println(a < b);   //false
System.out.println(a <= b);  //false
System.out.println(a == b);  //false
  • 逻辑运算符(也叫 布尔运算符)

            &     逻辑与【并且】(两边的算子都是true,结果才是true)
            |      逻辑或【或者】(两边的算子只要是一个是true,结果就是true)

System.out.println( 5 > 3 & 5 > 2 );  //true
System.out.println( 5 > 3 & 5 > 7 );  //false
System.out.println( 5 > 3 | 5 > 7 );  //true

            !      逻辑非(取反,!false就是true,!true就是false,这是一个单目运算符)

System.out.println( !true );   //false
System.out.println( !false );  //true

            ^      逻辑异或(两边的算子只要不一样,结果就是true)

System.out.println(true ^ false);  //true
System.out.println(false ^ false); //false
System.out.println(true ^ true);   //false

            &&  短路与
            ||     短路或

* 逻辑运算符要求两边的算子都是布尔类型,并且逻辑运算符最终的运算结果也是一个布尔类型。
* 短路与 和 逻辑与最终的运算结果是相同的,只不过短路与存在短路现象。( 短语或 和 逻辑与 同理)

* 什么情况下发生短路现象呢?
            - 发生短路或:第一个表达式执行结果是true,会发生短路或。
            - 发生短路与:第一个表达式执行结果是false,会发生短路与。

//逻辑与
int x = 10;
int y = 8;
System.out.println( x < y & ++x < y);
System.out.println(x);   //11

//短路与
int m = 10;
int n = 8;
//m < n 结果是false,整个表达式结果已经确定是false,所以后面的表达式没有执行,这种现象被称为短路现象。
//短路与才会有短路现象,逻辑与是不会存在短路现象的。
System.out.println( m < n && ++m < n);
System.out.println(m);    //10

 * 什么时候选择使用逻辑与运算符?什么时候选择使用短路与运算符?
        从某个角度来看,短路与更智能。由于后面的表达式可能不执行,所以执行效率较高。这种方式在实际的开发使用较多。短路与比逻辑与使用的多,短路与更常用。但是,在某些特殊的业务逻辑当中,要求运算符两边的算子必须全部执行,此时必须使用逻辑与,不能使用短路与,使用短路与可能导致右边的表达式不执行。

  • Java中的 "+" 运算符

        +运算符在java语言当中有两个作用:
                - 加法运算,求和
                - 字符串的连接运算     
        * 当"+"运算符两边的数据都是数字的话,一定是进行加法运算。
        * 当"+"运算符两边的数据只要有一个数据时字符串,一定会进行字符串连接运算,
          并且,连接运算之后的结果还是一个字符串类型。
        简单来说,  
                  数字 + 数字 ---> 数字【求和】
                  数字 + "字符串" ---> "字符串"【字符串连接】

        * 在一个表达式当中可以出现多个"+",在没有添加小括号的前提下,遵循自左向右的顺序一次运算。

System.out.println(10 + 20 + 30);  //这里的加号也是求和
System.out.println(10 + 20 + "30");  //自左向右的顺序一次运算,第一个加号是求和,第二个是字符串连接
System.out.println(10 + (20 + "30"));  //102030
  • 赋值运算符

赋值运算符包括两种:基本的赋值类运算符(=)、扩展的赋值运算符(+=, -+, /=, %=)

        - 基本赋值运算符

int i = 10;
System.out.println(i);  //10

i = i + 5;
System.out.println(i);  //15

赋值类的运算符优先级:先执行等号右边的表达式,将执行结果赋值给左边的变量

以 += 为例,其他的扩展的赋值运算符类似。

byte i = 10;
i += 5;    //等同于: i = (byte)(i + 5);
i += 128;   //可以,等同于:z = (byte)(z + 128);
System.out.println(i);   //【损失精度】
	
int k = 10;
k += 5;    //等同于:k = (int)(k + 5);
	
long x = 10L;
int y = 20;
y += x;    //等同于:y = (int)(y + x);

扩展类的赋值运算符不改变运算结果类型,假设最初这个变量的类型是byte类型,无论怎么样进行追加或追减,最终该变量的数据类型还是byte类型。【有可能会造成精度丢失】

注意:编译器只检测语法,不运行程序

byte b = 10;  //10没有超过byte取值范围,可以直接赋值
//b = 15; //编译通过,15没有超过byte取值范围

//编译错误,编译器只检测语法,不运行程序,编译器发现b+5的类型是int类型,b变量的数据类型是byte,大容量向小容量转换需要加强制类型转换符,所以以下程序编译报错。
//b = b + 5;   //错误
		
//纠正错误
b = (byte)(b + 5);   //可以
System.out.println(b);   //15

下面这种使用 += 运算符就可以编译成功

byte x = 10;
x += 5;   //可以,该句等同于:x = (byte)(x + 5)
System.out.println(x);   //15

  • 三目运算符【也叫三元运算符,条件运算符】

        * 语法规则:
            布尔表达式 ? 表达式1 : 表达式2
        * 三目运算符的执行原理?
            当布尔表达式的结果是 true 的时候,选择 表达式1 作为整个表达式的执行结果
            当布尔表达式的结果是 false 的时候,选择 表达式2 作为整个表达式的执行结果

boolean sex = false; //布尔类型的变量
//sex ? '男' : '女'; //编译报错,因为它不是一个完整的java语句
		
char c = sex ? '男' : '女';
System.out.println(c);      //女
  • 位运算符

        >>          <<

位运算符是对二进制位进行操作的,效率上会比其他运算符要快一些。

>> 1 二进制右移1位。

<< 2 二进制右移2位。

// 10的二进制位是:     0000 1010 【10】
// 10的二进制右移1位是:0000 0101 【5】
System.out.println(10 >> 1); //5

// 10的二进制位是:0000 1010 【10】
// 10的二进制右移1位是:0001 0100 【20】
System.out.println(10 << 1);  // 20

简单来说,就是 右移1位就是除以2,左移1位就是乘以2

控制语句

  • if 语句  --> 选择结构

        if 语句,属于选择结构,if语句又被称为分支语句/条件控制语句。

        if语句的语法结构:有以下四种编写方式

        - 第一种:

if(布尔表达式){
        java语句;
        ........
}

        - 第二种:

if(布尔表达式){
        java语句;
        .....

}else if(布尔表达式){
        java语句;
         .....
}else if(布尔表达式){
        java语句;
         java语句;
         ....
}.....

        - 第三种:【注意:以下编写方式都带有else分支,这两种方式可以100%保证会有分支执行】

if(布尔表达式){
        java语句;
        .....    
}else{
        java语句;
        ....
}

        - 第四种:

if(布尔表达式){
         java语句;
         .....
}else if(布尔表达式){
         java语句;
        .....
}else if(布尔表达式){
         java语句;
         ....
}else{
         java语句;
         .....
}

【重点】:对于java中的 if 语句来说,只要有一个分支执行,整个if语句全部结束。

        - "所有的控制语句"都是可以嵌套使用的,只要合理嵌套就行。还是要注意代码的编写格式的,该缩进缩进,该对齐对齐,看上去也很舒服。

if(){

        if(){

        }

}else{

        if(){

        }else{

        }

}

        - if语句的分支中只有一条java语句的话,大括号可以省略不写。不过这样不推荐使用。

if(true/false)

        一条java语句;

       - 还有可能出现错误

boolean sex = false;
if(sex)
	System.out.println("男");
	//System.out.println("嘿嘿");  //没有花括号,只能控制一条java语句
else     //去掉上句注释,此处出现编译错误
	System.out.println("女");

        - 还是希望像下面代码一样,带上花括号的,这样也方便以后的代码修改

double num= 1.0;  
//double num = 6.0;  

//判断语句
if(num < 5){
	System.out.println("大于5!");
}

        - 用 if 语句做一个简单的程序

        键盘上获取数据Scanner

                在这之前,先解释以下怎么从键盘上获取数据Scanner

System.out.println();  负责向控制台输出【从内存到控制台,输出的过程,这是从内存中出来】
接收用户键盘输入,从"键盘"到"内存"。【输入的过程,到内存中去】

//第一步:创建键盘扫描器对象
Scanner s = new Scanner(System.in);
        
//第二步:调用Scanner对象的next()方法开始接收用户键盘输入,程序执行到这里会停下来,等待用户的输入,当用户输入的时候,并且最终敲回车键的时候,键盘的信息会自动赋值给userInputContent,程序执行到这里,用户输入的信息已经到内存中了。
//String userInputContent = s.next();     //接收文本【以字符串的形式接收】 
int num = s.nextInt(); //接收数字【以整数型int的形式来接收】
      
System.out.println("您输入的数字是:" + num);

     需要导入 java.util.Scanner 这个包,如果没导入这个包可以使用全限定名称,创建键盘扫描器对象

//第一步:创建键盘扫描器对象

java.util.Scanner s = new java.util.Scanner(System.in); //全限定名称

         假设给定一个热的年龄(这个年龄需要从键盘输入),根据年龄来判断这个人出入生命的哪个阶段,年龄必须在[0-150]

import java.util.Scanner;

public class IfTest{

	public static void main(String[] args){
		
		//接收键盘输入:年龄【输入的时候必须输入数字】
		Scanner s = new Scanner(System.in);
		System.out.print("请输入您的年龄:");  //输出提示信息
		int age = s.nextInt();     //停下来等待用户输入
		
		String str = "老年";
		if(age < 0 || age > 150){
			str = "输入年龄不合法!";
		}else if(age <= 5){
			str = "幼儿";
		}else if(age <= 10){
			str = "少年";
		}else if(age <= 18){
			str = "青少年";
		}else if(age <= 35){
			str = "青年";
		}else if(age <= 55){
			str = "中年";
		}
		System.out.println(str);
	}
}
  •  switch  --> 选择结构

* switch语句也属于选择结构,也会是分支语句        
* switch语句的语法结构:

switch(int或String类型的字面值或变量){
        case int或String类型的字面值或变量 :
                 java语句;
                .....
                break;
        case int或String类型的字面值或变量 :
                 java语句;
                java语句;
                  .....
                break;
        .....
        default :
                java语句;
                .....
}

* switch语句的执行原理:
      switch后面小括号当中的"数据"和case后面的"数据"进行一一匹配,匹配成功的分支执行。按照自上而下的顺序一次匹配。匹配成功的分支执行,分支当中最后有"break;"语句的话,整switch语句终止。【注意】在这里break用来终止switch的语句执行,后面循环语句,会介绍的。

int num = 1;
switch(num){
    case 1 : 
        System.out.println("这是星期一");
        break;
    case 2 : 
		System.out.println("这是星期二");
		break;
	case 3 : 
		System.out.println("这是星期三");
		break;
	default :
		System.out.println("输入有误!");
}

上面代码的输出结果

这是星期一

匹配成功的分支执行,分支当中没有"break;"语句的话,直接进入下一个分支执行(不进行匹配),这种现象被称为case穿透现象

int num = 1;
switch(num){
    case 1 : 
        System.out.println("这是星期一");
    case 2 : 
		System.out.println("这是星期二");
	case 3 : 
		System.out.println("这是星期三");
	default :
		System.out.println("输入有误!");
}

上面代码的输出结果

这是星期一

这是星期二

这是星期三

输入有误!

所有分支都没有匹配成功,当有default的语句的话,会执行default分支当中的程序。

int num = 4;
switch(num){
    case 1 : 
        System.out.println("这是星期一");
        break;
    case 2 : 
		System.out.println("这是星期二");
		break;
	case 3 : 
		System.out.println("这是星期三");
		break;
	default :
		System.out.println("输入有误!");
}

上面代码的输出结果

输入有误!

* case可以合并:

int num = 0;  // int num = 1;
switch(num){
    case 1 : case 0 :
        System.out.println("这是星期一");
        break;
    case 2 : 
		System.out.println("这是星期二");
		break;
	case 3 : 
		System.out.println("这是星期三");
		break;
	default :
		System.out.println("输入有误!");
}

无论变量num是0 还是 1,结果都输出

这是星期一

可以使用switch语句做一个简单的计算机程序

public class SwitchTest{
	
	public static void main(String[] args){
		
		java.util.Scanner s = new java.util.Scanner(System.in);
		System.out.println("欢迎使用简单计算器系统:");
		System.out.print("输入第一个数字:");
		int num1 = s.nextInt();
		System.out.print("输入运算符:");
		String operator = s.next();
		System.out.print("输入第二个数字:");
		int num2 = s.nextInt();
		
		int result = 0;
		switch(operator){
			case "+" :
				result = num1 + num2;
				break;
			case "-" :
				result = num1 - num2;
				break;
			case "*" :
				result = num1 * num2;
				break;
			case "/" :
				result = num1 / num2;
				break;
			case "%" :
				result = num1 % num2;
				break;
			default :
				System.out.println("输入有误!");
				break;
		}
		System.out.println("运算结果为:" + num1 + operator + num2 + " = " + result);
	}
}
  • for 语句  -->  循环结构

        - 循环结构:

        在程序当中总有一些需要反复的/重复的执行的代码,假设没有循环结构,那么这段需要重复执行的代码自然是需要重复编写的。代码无法得到重复使用。所以多数编程语言都是支持循环结构的。将来把需要反复执行的代码片段放到"循环体",再联合"计数器",共同控制这段需要反复执行的代码。

//需求:输出数字1-10
System.out.println(1);
System.out.println(2);
System.out.println(3);
System.out.println(4);
System.out.println(5);
System.out.println(6);
System.out.println(7);
System.out.println(8);
System.out.println(9);
System.out.println(10);

       使用循环结构来代替以上所有反复执行的代码快,可以减少代码量

//需求:输出数字1-10
for(int i = 1; i <= 10; i++){
	System.out.println(i);
}

        - 基本上所欲的编程语言支持的循环包括三种:
            * for循环
            * while循环
            * do...while循环

        - for循环的语法结构:

for( 初始化表达式; 布尔表达式; 更新表达式 ){
       循环体 //是需要重复执行的代码片段【循环体:有java语句构成】        
}

        - for循环的执行原理

          * 初始化表达式、布尔表达式、更新表达式都不是必须的!【但是两个分号是必须的】

//死循环
for(;;){
	System.out.println("死循环");
}

          * 初始化表达式最先执行,并且在整个for循环当中只执行一次。
          * 布尔表达式必须是true/false,不能是其他值。

        - for循环的执行过程:

         先执行初始化表达式,并且该表达式只执行一次,判断布尔表达式的结果是true,还是false,如果布尔表达式true,执行循环体,执行更新表达式(重复执行判断布尔表达式的结果,执行循环体,执行更新表达式),直到布尔表达式false,循环结束。
        - 以下的for循环当中"i"变量的作用域是仅限于当前for循环内部使用。

for(int i = 0; i < 10; i++){
	System.out.println("i -----> " + i);
}
//这个i变量不可以在for循环外面访问
//System.out.println("i = " + i);    //编译报错

        - 这也是根变量 “i” 的作用域有关的

public void test(){
	int i = 0; //test方法作用域当中的i变量
	for(; i < 10; i++){
		System.out.println("i = " + i);
	}
	//这里可以访问test方法作用域当中的i变量
	System.out.println("i -----> " + i);   //10
}  
    

        - for 循环的更新表达式 可以根据自己的需求而改变的

//输出1~10中所有的偶数
for(int i = 2; i <= 10; i += 2){
	System.out.println("i ------> " + i);
}

        - 也可以写成这种形式,不过一般情况下,不会这样使用的

for(int i = 0; i < 10;){
	System.out.println("计数器 -----> " + i); //0 1 2 3 4 5 6 7 8 9
	i++;
}

        - 控制语句之间,是可以相互嵌套的

for(int i = 1; i <= 10; i++){
	if(i % 2 != 0){
		System.out.println("奇数 -----> " + i);
	}	
}

        - 使用for循环嵌套,做一个九九乘法表

for(int i = 1; i <= 9; i++){  //外层循环9次
	//处理当前行,将当前行中的所有的项目全部输出
	for(int j = 1; j <= i; j++){
		System.out.print(i + "*" + j + "=" + (i * j) + " ");
	}	
	System.out.println(); //换行
}

foreach(也叫作 增强for循环)

        - JDK5.0之后推出了一个新特性

        - 语法结构:

for (元素类型 变量名 : 数组或集合) {
        System.out.println(变量名);
}

可以一定程度上的简化数组和集合的输出,但是有一个缺点:没有下标

下面以数组为例,

// int类型数组
int[] arr = {432, 4, 56, 76, 45};

// 遍历数组(普通for循环)
for (int i = 0; i < arr.length; i++) {
    System.out.println(arr[i]);
}

for(int data : arr) {
    // data就是数组中的元素(数组中的每一个元素。)
    System.out.println(data);
}
  • break语句

        break是java语言当中的关键字,break + ";" 可以成为一个单独的完整的java语句:  break;
        - break语句使用在switch语句当中,用来终止switch的语句执行。
        - break语句同样可以使用在循环语句当中,用来终止循环的执行。

         break;语句使用在for、while、do..while循环语句当中用来跳出循环,终止循环的执行。因为当程序循环到某个条件的时候,后续的循环没必要执行了,再执行也是耗费资源,所以可以终止循环,这样可以提高程序的执行效率。     

        - break终止哪个循环呢?            
             在默认情况下:break语句终止的是离它最近的循环语句。

for(int j = 0; j < 3; j++){
	for(int i = 0; i < 10; i++){
		if(i == 5){
            //当前的break语句终止的是内层for循环,因为这个for离它最近,这里的break语句不会影响到外层for循环
			break;    		
        }
		System.out.println("i -----> " + i);			
	}	
	System.out.println();
}

        当然也可以指定终止某个循环,需要给循环起名,采用这种语法:break 循环名称;

        不过这种方式,使用的很少。

//给for循环起名for1
for1:for(int j = 0; j < 3; j++){
	//给for循环起名for2
	for2:for(int i = 0; i < 10; i++){
		if(i == 5){
			break for1;  //终止for1循环
		}
		System.out.println("i -----> " + i);			
	}
}

以上以for循环为例来说明break;语句。其他循环语句类似。

  • continue语句

        continue也是一个continue关键字加一个分号构成一个单独的完整的java语句,主要出现循环语句当中用来控制循环的执行。

        - break和continue的区别?
             * break表示循环不执行了,跳出循环,终止循环。
             * continue表示终止当前"本次"循环,直接进入下一次循环继续执行。

for(int i = 0; i < 10; i++){
	if(i == 5){
		break;				
	}
	System.out.println("i --->" + i);  //0 1 2 3 4
}
		
for(int i = 0; i < 10; i++){
	if(i == 5){
		continue;  //只要这个语句执行,当前本次循环停止,直接进入下一次循环"继续"执行
	}
	System.out.println("i --->" + i); //0 1 2 3 4 6 7 8 9
}
		

continue也有这样的语法:
             continue 循环名称;【作为了解】

myFor:for(int i = 0; i < 10; i++){
	if(i == 5){
		continue myFor;				
	}
	System.out.println("i --->" + i);  //0 1 2 3 4 6 7 8 9
}
  • while 语句  -->  循环结构

        - while循环的语法结构:
                    while(布尔表达式){
                        循环体;
                    }

        - while循环的执行原理:

                先判断布尔表达式的结果,如果是true,执行循环体(重复执行,判断布尔表达式的结果,如果是true,执行循环体),直到布尔表达式的结果为false时,循环结束。
        - while循环的循环次数:
                        0 ~ N次
 【注意】:while循环的循环体可能执行次数为0次。

使用while循环的时候,一定要注意死循环,如果编译器检测到会提醒

//死循环
while(true){
	System.out.println("死循环");
}
//编译器检测到该程序永远都无法被执行,所以编译报错。
System.out.println("哈哈!!!");

但是也会存在编译器检测不到是时候

int i = 10;
int j = 5;
// 死循环
while(i > j){
	System.out.println("嘿嘿!!!");
}
System.out.println("哈哈!!!");

因为在编译的时候,编译器无法“得出”这两个变量究竟是那个大。

  • do...while 循环

        - do..while循环的语法结构:
                    do{
                        循环体;
                    }while(布尔表达式);

int a = 1;
do{
	System.out.println(a);  //1 2 3 4 5 6 7 8 9 10
	a++;
}while(a <= 10);

          - do..while循环的执行原理:

                先执行循环体,再判断布尔表达式的结果,如果是true(重复执行,先执行循环体,再判断布尔表达式的结果,如果是true),直到布尔表达式的结果为false时,循环结束。
        - do..while循环的循环体代码片段执行次数是:1-N次【至少一次】
【注意事项】:do..while循环语句最终有一个"分号"别丢了。

与while循环语法类似,也要注意避免死循环

//死循环
int i = 1000;
do{
	System.out.println(i);
}while(i > 100);
  • 方法

        - 方法的本质是什么?

    方法就是一段代码片段,并且这段代码片段可以完成某个特定的功能,并且可以被重复使用。

通常我们使用这个方法,被称为方法的"调用/invoke"。

        方法定义在类体当中,在一个类当中可以定义多个方法,方法编写的位置没有先后顺序,可以随意。【方法体当中不能再定义方法!!!!!】方法体有java语句构成,方法体当中的代码遵守自上而下的顺序一次执行。

        - 定义方法的语法结构:

                [修饰符列表] 返回值类型 方法名(形式参数列表){
                        方法体;
                }

        对以上的语法结构进行解释说明:
            1、关于修饰符列表:
                * 可选项,不是必须的
                * 方法的修饰符列表当中有static关键字的话,怎么调用这个方法?
                    - 类名.方法名(实际参数列表);
            2、返回值类型:
                * 什么是返回值?
                    一个方法是可以完成某个特定功能的,这个功能结束之后大多数都是需要返回最终执行结果的,执行结果可能是一个具体存在的数据。而且这个具体存在的数据就是返回值。
                * 返回值类型?
                    返回值是一个具体存在的数据数据都是有类型的,此处需要指定的是返回值的具体类型。
                * 返回值类型都可以指定哪些类型呢?
                    java任意一种类型都可以,包括基本数据类型和所有的引用数据类型。
                * 也可能这个方法执行结束之后不返回任何数据, java中规定,当一个方法执行结束之后不返回任何数据的话,返回值类型位置必须编写:void关键字。
                * 返回值类型可以是:
                    byte,short,int,long,float,double,boolean,char,String,void....
                * 返回值类型若不是void,表示这个方法执行结束之后,必须返回一个具体的数值。当方法执行结束的时候没有返回任何数据的话编译器报错。
                    怎么返回值呢?代码怎么写呢?
                        "return 值;",并且要求"值"的数据类型必须和"方法"的返回值类型一致,不然编译器报错。   
                * 返回值类型是void的时候,在方法体当中不能编写 "return 值;" 这样的语句。但是要注意可以编写"return;"这样的语句。                 
                * 只要带有return关键字的语句执行,return语句所在的方法结束。【不是JVM结束,是return所在的方法结束】
            3、方法名:
                * 只要是合法的标识符就行
                * 方法名最好见名知意
                * 方法名最好的动词
                * 方法名首字母要求小写,后面每个单词首字母大写
            4、形式参数列表:【简称 形参】
                * 形参是么局部变量:int a; double b; float c; String s;....
                * 形参的个数可以是:0-N个
                * 多个形参之间用"逗号"隔开
                * 形参中起决定性作用的是形参的数据类型,形参的名字就是局部变量的名字。
                 例如:
                         方法定义
                         public static int sum(int a, int b){
                         }
                         方法调用
                         sum("abc", "def");  //编译器报错
                         sum("123", 20);     //("123", 20)是实参列表
            5、方法体必须由大括号括起来,方法体当中的代码有顺序,遵循自上而下的顺序依次执行。并且方法体由java语句构成,每个java语句以";"结尾。

main方法

        - main方法是SUN规定的主方法,必须是固定的编写方式,也是程序的入口

//public表示公开的,class表示定义类,MethodTest是一个类名
public class MethodTest{  //表示定义一个公开的类,起名MethodTest,由于是公开的类,所以源文件名必须:MethodTest

	//类体
	//类体中不能直接编写java语句,除声明变量之外,方法出现在类体当中
	
	//方法
	//public表示公开的,static表示静态的,void表示方法执行结束之后不返回任何数据
	//main是方法名:主方法
	//(String[] args) :形式参数列表,其中String[]是一种引用数据类型,args是一个局本变量的变量名,所以以下只有args这个局部变量的变量名是随意的
	//主方法就需要这样固定编写,这是程序的入口。【SUN规定的,必须这样写】
	public static void main(String[] args){			
		//这里的程序一定会执行
		//main方法是JVM负责调用的,是一个入口位置
		//从这里作为起点开始执行程序
		//既然是这样,我们就可以在这里编写java语句来调用其他的方法
		System.out.println("main方法执行了");
		
	}
}

        - 方法的调用不一定在main方法当中,可以在其他方法当中。只要是程序可以执行到的位置,都可以去调用其他方法。

public class MethodTest01{
	
	public static void sum(int a, int b){
		System.out.println(a + " + " + b + " = " + (a + b));
		MethodTest01.doSome();	 //调用doSome方法	
	}
	//主方法main
	public static void main(String[] args){
		MethodTest01.sum(1, 2);	 //调用sum方法
	}
	public static void doSome(){
		System.out.println("Over doSome!!");
	}
}

        - 方法调用的时候实参和形参要求个数对应相同,数据类型对应相同。类型不同的时候要求能够进行相应的自动类型转换

public class MethodTest02{
	
	public static void main(String[] args){
		//MethodTest02.sum(); //编译报错:参数数量不同
		//MethodTest02.sum(true, false); //编译错误:实参和形参的类型不对应
		
        MethodTest02.sum(10L, 20L); //可以
		MethodTest02.sum(10, 20); //存在自动类型转换:int ---> long
		
		//MEthodTest02.sum(3.0, 20); //编译错误:参数的类型不对应
		MethodTest02.sum((long)3.0, 20); //可以
	}
	public static void sum(long a, long b){	
		System.out.println(a + " + " + b + " = " + (a + b));
	}
}

        - 方法的调用:
        1、方法的修饰符列表当中的static关键字,完整的调用方式是:类名.方法名(实参列表);
        2、但是,有的时候"类名."可以省略,什么情况下可以省略呢?
                m1(){
                    m2();
                }
            m1方法和m2方法在同一个类体当中的时候,"类名."可以省略不写。
        3、建议在一个java源文件当中只定义一个class,比较清晰。

public class MethodTest03{
	
	public static void main(String[] args){
		MethodTest03.m();  //调用方法
		
		m();  //对于方法的修饰符列表当中有static关键字的:"类名."可以省略不写
		A.doOther();  //调用其他类【不是本类中的】中的方法
		
		//编译报错:"类名."省略以后,默认从当前类中找"doOther"方法,在当前类中该方法不存在。
		//doOther();
	}
	public static void m(){
		System.out.println("m method execute!");		
		MethodTest03.m2();  //完整的方式		
		m2(); //省略的方式
		
		A.m2(); //不想调用当前本类当中的m2方法,这个时候就必须添加"类名."了。
	}
	public static void m2(){
		System.out.println("m2 execute!");
	}
}

class A{
	public static void doOther(){
		System.out.println("A's doOther method invoke!");
	}
	public static void m2(){
		System.out.println("A's m2 method invoke!");
	}
}

        【注意】:
            当前行的程序在没有结束的时候,下一行代码是无法执行的。只要记住方法中的代码是自上而下的顺序依次执行即可。

public class MethodTest04{
	
	public static void main(String[] args){
		System.out.println("main begin");
		m1();
		System.out.println("main over");
	}
	public static void m1(){
		System.out.println("m1 begin");
		m2();
		System.out.println("m1 over");
	}
	public static void m2(){
		System.out.println("m2 begin");
		m3();
		System.out.println("m2 over");
	}
	public static void m3(){
		System.out.println("m3 begin");
		System.out.println("m3 over");
	}
}

上面的程序结果如下:

        main begin
        m1 begin
        m2 begin
        m3 begin
        m3 over
        m2 over
        m1 over
        main over

        - 方法的返回值类型不是void的时候。
           *  返回值类型不是void的时候,要求方法必须保证百分百的执行"return 值;"这样的语句来完成值得返回。没有这个语句编译器会报错。

        下面是return正确案例

//可以,但是具体的方法体中编写的代码无法满足当前的需求。
public static int divide(int a, int b){
    return 1;
}

public static int divide(int a, int b){
    int c = a / b;
    return c;
}

        下面是return错误案例

//编译报错:缺少返回语句
public static int divide(int a, int b){

}

//编译报错:缺少返回值
public static int divide(int a, int b){
    return;
}

//编译报错:方法定义的时候要求返回一个int类型,此时返回布尔类型,类型不兼容。
public static int divide(int a, int b){
    return true;
}

           *  一个方法有返回值的时候,当我们调用这个方法的时候,方法返回了一个值,对于调用者来说,这个返回值可以选择接收,也可以选择不接受,但是大部分情况下,我们都是选择接收到的。

public class MethodTest{
	
	public static void main(String[] args){
		//调用方法
		divide(10, 3);  //这里没有接收这个方法的返回数据
		//这里接收一下方法执行结束之后的返回值
		//采用变量接收,变量的数据类型需要和返回值的数据类型相同,或者可以自动类型转换。
		//boolean i = divide(10, 3);   //编译报错,类型不兼容
		
		//赋值运算符的右边先执行,将执行结果赋值左边的变量
		int i = divide(10, 3);
		System.out.println(i);
		
		long h = divide(10, 3);
		System.out.println(h);
		System.out.println(divide(10, 3));	
	}
	public static int divide(int a, int b){		
		System.out.println("divide method!");
		return a / b;
	}	
}
  • return关键字

        - 带return关键字的java语句只要执行,所在的方法执行结束。
        - 在同一个作用域当中,return语句下面不能编写任何代码,因为这些代码永远都执行不到,所以编译报错。

public static int m(){
	int a = 10;
	if(a > 3){
		return 1;
		//这里不能编写代码,编译错误,因为无法访问的语句
		//System.out.println("m method!");
	}
	System.out.println("m method!!!!!!"); //这里的代码有可能执行到,所以编译不会报错
	return 0;
	//System.out.println("hello!"); //编译错误,无法访问的语句
}

        - 经典return错误案例

//编译报错:缺少返回语句,以下程序编译器认为无法百分百保证"return 1;"会执行。
public static int m(){
        int a = 10;
        if(a > 3){
            return 1;
        }
}

        - 上一个案例改进

//以下程序可以保证"return 1; 或 return 0;" 执行。编译通过。 

public static int m(){
        int a = 10;
        if(a > 3){
            return 1;
        }
        return 0;
    }

        - 返回值类型是void的方法当中使用"return ;"语句。
        "return;"语句出现在返回值为void的方法当中,主要是为了用来结束当前方法。

public class ReturnTest{
	
	public static void main(String[] args){
		m();
		for(int i = 10; i > 0; i--){
			if(i == 9){
				return;    //结束的是main方法
			}
			System.out.println("i ---> " + i);
		}
		System.out.println("hello!!");
	}	
	public static void m(){
		for(int i = 0; i < 10; i++){
			if(i == 5){
				//return;    //不是终止for循环,终止的是m()方法
				break;   // 终止的是for循环
			}
			System.out.println("i ---> " + i);
		}
		System.out.println("m method!!");
	}
}

【注意】:对于结果类型为空的方法,无法返回值

public static void m(){
        return;
    }

  • 方法内存执行分析

方法在执行过程当中,在JVM中的内存是如何分配的呢,内存是如何变化的?
        1、方法只定义,不调用,是不会执行的,并且在JVM中也不会给该方法分配"运行所属"的内存空间。只有在调用这个方法的时候,才会动态的给这个方法分配所属的内存空间。
        2、在JVM内存划分上有这样三块主要的内存空间(当然除了这三类之外还有其他的内存空间):
            * 方法区内存
            * 堆内存
            * 栈内存
        3、关于栈数据结构:
            * 栈:stack,是一种数据结构。
            * 数据结构反应的是数据的存储形态。


            * 常见的数据结构:
                - 数组
                - 队列
                - 栈
                - 链表
                - 二叉树
                - 哈希表/散列表
                ....
        4、方法代码片段存放在哪里?方法执行的时候执行过程的内存在哪里分配?
            * 方法代码片段属于.class字节码文件的一部分,字节码文件在类加载器的时候,将其放到了方法区当中。所以JVM中的三块主要的内存空间中方法区内存最先有数据,存放了代码片段。
            * 代码片段虽然在方法区内存当中只有一份,但是可以被重复调用。每一次调用这个方法的时候,需要给方法分配独立的活动场所,在栈内存中分配。【栈内存中分配方法运行的所属内存空间】
        5、方法在调用的瞬间,会给该方法分配内存空间,会在栈中发生压栈动作,方法执行结束之后,给该方法分配的内存空间全部释放,此时发生弹栈动作。
             * 压栈:给方法分配内存
             * 弹栈:释放该方法的内存空间


        6、局部变量在"方法体"中声明。局部变量运行阶段内存在栈中分配。

【重点】:
        方法调用的时候,在参数传递的时候,实际上传递的是变量中保存的那个"值"传过去了。 

  • 方法重载

        - 方法重载机制(Overload)

                功能虽然不同,但是功能相似的时候,可以让出让程序员使用,这些方法的时候就像在使用同一个方法一样,这样程序员以后编写代码比较方便,也不需要记忆更多的方法名。代码也会很美观。

        - 前提:

        功能相似的时候,方法名可以相同。但是,功能不同的时候,尽可能让两个方法名不同。

        - 什么条件满足之后构成了方法重载?
            * 在同一个类当中
            * 方法名相同
            * 参数列表不同:
                - 数量不同
                - 顺序不同
                - 类型不同

public class OverloadTest{
	
	public static void main(String[] args){
		m1();
		m1(10);
		
		m2(1, 2.0);
		m2(2.0, 1);
		
		m3(10);
		m3(3.0);
	}
	//以下两个方法构成重载
	public static void m1(){}
	public static void m1(int a){}
	//以下两个方法构成重载
	public static void m2(int a, double b){}
	public static void m2(double a, int b){}
	//以下两个方法构成重载
	public static void m3(int a){}
	public static void m3(double b){}		
}

         - 方法重载和什么有关系,和什么没关系?
            * 方法重载和方法名 + 参数列表有关系

//编译错误:以下不是方法重载,是反生了方法重复了
public static void m4(int a, int b){}
public static void m4(int b, int a){}


            * 方法重载和返回值类型无关

// 以下编译报错

public static void x(){}
public static int x(){
        return 1;
}


           * 方法重载和修饰符无关

//编译错误:方法重载和修饰符无关
void y(){}
public static void y(){}

  • 方法递归

关于方法的递归调用
        1、什么是递归?
            方法自身调用自身。
            a(){
                a();
            }
        2、递归是很耗费内存的,递归算法可以不用的时候尽量别用。
        3、以下程序运行的时候发生了这样的一个错误【不是异常,是错误Error】
            java.lang.StackOverflowError【栈内存溢出错误】
            错误发生无法挽回,只有一个结果,就是JVM停止工作。

下面代码就会出现错误。

public class RecursionTest{
	//主方法
	public static void main(String[] args){
	
		System.out.println("main begin");
		doSome(); //调用doSome方法		
		System.out.println("main over");
	}
	//以下代码片段虽然只有一份,但是可以被重复的调用,并且只要调用doSome方法就会在栈中新分配一块所属的内存空间。
	public static void doSome(){
		System.out.println("doSome begin");
		doSome();  //这行代码不结束,下一行程序是不能执行的
		System.out.println("doSome over");
	}
}

        4、递归必须有结束条件,没有结束条件一定会发生栈内存溢出错误。递归即使有了结束条件,即使结束条件是正确的,也有可能发生栈内存溢出错误,因为递归的太深了。      
        5、递归的原理图:

   上图中,红色箭头代表方法的调用,蓝色箭头代表着方法的返回。

【注意】:
            递归可以不使用尽量别用。但是有些情况下该功能的实现必须依靠递归方式。

案例:使用递归,计算1~N的和【可以不用递归,尽量不用递归】

public class RecursionTest01{
	
	public static void main(String[] args){	
		n = 10;
		retValue = sum(n);  //调用sum方法
		System.out.println(retValue);			
	}
	//单独的定义一个方法,这是一个独立的功能,可以完成1~N的求和,递归
	public static int sum(int n){
		if(n == 1){
			return 1;
		}
		return n + sum(n-1);
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值