第二章:Java基础语法
数据类型
01、 变量运算符02、程序流程控制
03、课后练习题
一、Java程序基本结构
1.1 基本结构
Java程序基本结构示例代码:
后面全是资料:
IDEA小技巧:
public static void main(String[] args) {} 这一串语句打出快捷键就是psvm,首字母小写的缩写
标识符:可以自己起名字的地方
变量、类名、数组名、参数名、方法名、成员变量名.....
变量与运算符
一、Java程序基本结构
前情回顾
还记得我们在上一章学过的Hello World程序是怎么写的吗?我们写了好几行代码,分别代表什么意思?为什么要这么写?
public class HelloWorld {
public static void main(String[] args) {
System.out.println("HelloWorld");
}
}
1. HelloWorld代表的是类名。类的概念,会在后面的面向对象部分学习。这里我们可以认为,所有的Java程序,必须写在一个类里。类是对同一类型相同事务提取出来共性的一个概念。
2. class是修饰类名的关键字。所有的类名之前,必须加class
3. {...}类名HelloWorld后面的大括号,是类的内容。大括号要前后对应。
4. 括号中的内容,称为main方法。是java程序的入口。以后我们学的多了,可以写很多种方法,a方法,v方法等。但是已经有main方法了,就不能重复定义了。
5. java编译器为每个类生成一个字节码文件(也就是后缀名为class的文件),且文件名与类名相同,同名的类有可能发生冲突。为了解决这一问题,java提供包来管理类名空间,什么是包呢,实际就是文件夹。相同的名字的类,在不同的包下,就像是同样的东西,放在不同的抽屉中一样.
6. 一个java源文件,可以有多个类,但是只能有一个公共类(由public修饰的类),而且经过编译之后,会生成与类名对应的字节码文件(有几个类就有几个字节码文件)。
面试题:static能改变变量的访问权限吗?static是静态的,通过类名直接访问。在Java里面,所有的访问权限,都是什么其他都不可能改变其访问权限。其他都不能改变,只是改变了调用方式。
二、关键字和保留字
正确识别java语言的关键字(keyword)和保留字(reserved word)是十分重要的。Java的关键字对java的编译器有特殊的意义,他们用来表示一种数据类型,或者表示程序的结构等。保留字是为java预留的关键字,他们虽然现在没有作为关键字,但在以后的升级版本中有可能作为关键字。 识别java语言的关键字,不要和其他语言如c/c++的关键字混淆。
保留字
保留字(reserved words):是语言已经定义过的字,一些保留字可能没有相对应的语法,考虑到扩展性,为了向后兼容不能再将其作为变量名。const和goto是java的保留字。 目前没在用,将来可能会用到。
关键字
关键字,是被Java语言赋予了特殊含义的单词。在给类、变量等命名是不要使用。 特点是所有字母都小写。(在很多编程软件中会显示出一种颜色)。见下图
详解:https://blog.csdn.net/ZytheMoon/article/details/78648288
接口就是一种规范,一种约束。
原始类型就是基本数据类型。
byte 一个字节 8位 bit
short 2个字节 16
int 4个字节 32
long 8个字节 64
形状类,老虎类,人类,吃类等。
final最终的就不能被修改。
synchronized 面试经常出现。
对象就是中国人,美国人,非洲人等。
谁来调用这个方法,this就是谁。
有些事已经自定义好的异常,有些事我们1自定义的异常。
goto保留关键字。不是Java关键字。
三、标识符及命名规范
3.1 标识符概述
应该说命名规范是一种约定,也是程序员之间良好沟通的桥梁。良好的命名规范可以为团队合作开发推波助澜,无论在项目开发,还是产品维护上都起到了至关重要的作用。
Java 对各种变量、方法和类、接口等要素命名时使用的字符序列称为标识符(在Java里面,所有可以自己起名字的地方都叫标识符)。
3.2 命名规范
/**
标识符测试
命名规则:
(1)标识符由字母、下划线“_”、美元符“$”和数字组成。空格也是不行。
(2)标识符不能以数值开头。
(3)不可以是Java的关键字和保留字。
(4)Java 标识符大小写敏感,且长度无限制。
(5)见名之意
(6)驼峰原则:首字母小写,多个单词组成的话,首个单词的首字母小写,之后每个单词的首字母都大写
命名规范:
java采用匈牙利命名规范,它的基本原则是名称要有明确的意义。具体要求为:
类名/接口首字母大写,如果包含多个单词,每个单词首字母都大写 XxxYyyZzz\Person
变量/方法首字母小写,如果包含多个单词,每个单词首字母都大写 age\useName
常量全部大写,多个单词组成,则每个单词由_分割 PI\SUBSITE_EVER
包名全部小写。我们在项目中,包名一律使用这种方式:
[cn.]com.公司名.项目名.模块名
com.newcapec.abgame.util
Java小技巧:
IdEA工具会自动编译我们的源代码,当我们的源代码出现红的时候,那就表示编译不通过
Ctrl+d是IDEA的复制快捷键
Java同一作用域里面,不能出现同名变量
**/
public class IdentifierTest {
public static void main(String[] args){
//String是用来定义字符串变量的
//int是用来定义整型的
String useName;
String useName01;
String useName_01;
String useName$01;
//String useName-01;
//String useName%01;
//String class;
String classes;
String realName;
//String realName;
String realname;
String name = "张三";
String sex = "男";
String 真实姓名 = "李克伟"; //强烈不推荐 标识符虽说可以出现中文,但是不要这么写
int age;
int $age;
int _age;
//int 2age;
}
}
四、变量
内存如何存放数据
电脑使用内存来记忆程序运行所使用的数据(程序中所有的数据都是存储在内存里面)
内存如何存储数据?
1、开房间(前台登记单人间、双人间、总统套间) 声明数据类型
2、入住
内存像旅馆
数据各式各样,要先根据数据的需求(即类型)为它申请一块合适的空间
已经将数据存入内存,但是:
怎么找到存入的数据?
内存地址不好记,怎么办?
通过内存中房间的别名找到数据存储的位置
通过变量名可以简单快捷的找到它存储的数据。
通过变量名可以简单快速地找到它存储的数据
4.1 变量的概念
//声明变量,即“根据数据类型在内存申请空间” 数据类型 变量名;
int num;
//赋值,即“将数据存储至对应的内存空间”
num = 100;
//使用变量,即“取出数据使用 ”
System.out.println(num);
//声明变赋值语法
int age = 100;
//重新赋值
age = 200;
age = 250;
String name = "张三";
判断1
public class Error1 { public static void main(String[] args) { String title; System.out.println( title ); } } //以上是否有错误?
先声明变量并赋值,然后才能使用
判断2
public class Error2 { public static void main(String[] args) { int %hour = 18; System.out.println(%hour); } } //以上是否有错误?
变量名不能以%开始
判断3
public class Error3 { public static void main(String[] args) { String name = "张三"; String name = "李四"; } } //以上是否有错误?
声明两个同名变量导致编译错误
4.2 变量的分类
按被声明的位置划分: 成员变量:方法外部、类的内部定义的变量 局部变量:方法或语句块(代码块)内部定义的变量 局部变量赋值才能使用 注意:类外面(类对应的大括号外面)不能有变量的声明不能有任何代码出现。
/*变量测试 在程序中存在大量的数据来代表程序的状态,其中有些数据在程序的运行过程中值会发生改变, 有些数据在程序运行过程中值不能发生改变,这些数据在程序中分别被叫做变量和常量。 程序运行过程中会发生改变的量,叫变量。程序运行过程中不允许发生改变的量,叫常量。 变量的本质: 其实就是内存的一个存储区域,该区域的数据可以在同一类型范围内不断变化, 不同数据存入具有不同内存地址的空间,相互独立。 变量是程序中最基本的存储单元,包括变量类型、变量名和存储的值。 变量就是存储数据的容器;用于在内存中保存数据 变量:一个数据存储空间的表示;不同数据存入具有不同内存地址的空间,相互独立。 该区域有自己的名称(变量名)和类型(数据类型,表示该区域能放什么样的值) 1、Java中每个变量必须先声明赋值,后使用 2、使用变量,只需要使用变量名,就可以得到该变量的值,例如:System.out.printIn(var); 3、Java是强类型语言,变量在声明的时候必须指定数据类型,后使用。 4、使用变量注意:变量的作用域在一对{ }之间有效。 * */ public class VariableTest { public static void main(String args[]){ //方式一:先声明,后赋值 指南:数据(变量)类型 变量名; 变量名 = 变量值; int myAge; //向内存中申请一块区域:用来存储int类型值,通过myAge指向这个内存区域 申请房间 myAge = 22; //入住房间 //方式二:声明并赋值 指南:数据类型 变量名 = 初始化值 和上面执行机制一样的 int yourAge = 33; System.out.println(myAge); System.out.println(yourAge); //myName呈现红色 报错:变量没有声明 必须先声明,后使用 //System.out.println(myName); //String myName; //局部变量:在方法内部声明的变量 //局部变量必须赋值才能调用,不然控制台语句myName波浪线报错 String myName = "李克伟"; System.out.println(myName); } }
4.3 变量的数据类型(面试题)
Java语言是一门强类型语言,也就是说,每个变量或者符号常量甚至一个方法都必须有明确的数据类型或者是返回值类型。在 Java 中,数据类型分为两种,分别是基本类型和引用类型。 基本类型一共有四大类八种基本数据类型,它们是:四种整型,两种浮点型,一种字符型和一种布尔型。 引用类型有类,接口和数组等(后面会详细学习)
int i = 100;
对于每一种数据都定义了明确的具体数据类型,在内存中分配了不同大小的内存空间。
Java基本数据介绍 1.boolean:数据值只有true或false,适用于逻辑计算,占一字节 2.byte:byte型(字节型)数据在内存中占用1个字节,表示的存储数据范围为:-128~127,因为第一位是符号位。一个字节8位。 3.char:char型(字符型)数据在内存中占用2个字节。char型数据用来表示通常意义上的字符。 (思考,char类型的变量能存放汉字吗?) 中文汉字字母符号都是字符占用一个字符。 4.short:short型(短整型)数据在内存中占用2个字节 5.int:int型(整型)数据在内存中占用4个字节。 6.long:long型(长整型)数据在内存中占用8个字节。 7.float:float型(单精度浮点型)数据在内存中占用4个字节。 8.double:double型(双精度浮点型)数据在内存中占用8个字节。
在java中,整形数据默认为int数据类型,浮点型默认为double数据类型,如果要表示long型数据或float型数据,要在相应的数值后面加上l、L或f、F,否则会出现编译问题。char是可以有存储范围的,可以用一个数值来表示它,所以也叫整数型。缺省数值其实就是默认值,局部变量就是默认值,数组的时候会说到。
public class VaribleTest01 { String ever = "地球"; //在方法外,类内部声明的变量,叫做成员变量; static String test = "Test";//由static修饰的成员变量,叫静态变量 int num; public static void main(String[] args){ /*按数据类型划分 基本数据类型:8种,byte、short、int、long、float、double、boolean、char; 整数类型:byte、short、int、long 浮点类型:float、double 布尔类型:boolean 字符类型:char 引用数据类型:类、接口、数组等; 字符串是引用数据类型 面试题:Java的八种数据类型有哪些?String是基本数据类型吗?Java数据类型划分? */ String name = "李克伟";//定义在方法内部的变量,叫局部变量 //static String name = "李克伟";//static不能修饰局部变量 System.out.println(name); //创建一个对象,通过对象来调用num VaribleTest01 VaribleTest01 = new VaribleTest01(); System.out.println(VaribleTest01.num);//对象调用成员变量 System.out.println(VaribleTest01.test);//对象调用静态变量 System.out.println(VaribleTest01.test);//类名调用静态变量 } }
4.3.1 整数类型
从小到大取值范围分别是:byte、short、int、long Java各整数类型有固定的表述范围和字段长度,不受具体 OS (operating system)的影响,以保证 java 程序的可移植性。 Java 的整型常量默认为 int 型,声明 long 型常量须后加 ‘l’ 或 ‘L’ 结尾,就是小写和大写 1个字节 = 8 bit ,每一个bit有两种情况 0 或1,所以就存在2的8次方种组合,就可以存储256个数,语言规定一半正,一半负,但是因为存在0,所以规定-128 -127 表数范围公式:-2^(位数-1)次幂~2^(位数-1)次幂-1 例如:-2^(8-1)~2^(8-1)-1 —— -2^7~2^7 - 1
byte b1 = 100; byte b1 = 128; //编译不通过 short s1 = -100; short s2 = (short)(b1+s1); long l1 = 100; //整数数值默认是int类型,3222233333超出了int的取值范围 //long L2 = 3222233333; //编译不通过 long L3 = 3222233333L; //编译通过 注意:在混合运算中byte、short、char直接转换为int。 使用过程中习惯用int类型,之后再考虑long类型。
4.3.2 浮点类型
与整数类型类似,Java 浮点类型也有固定的表数范围和字段长度,不受具体OS的影响。
Java 的浮点型默认为 double 型,声明 float 型变量,须后加 ‘f’ 或 ‘F’。
float f1 = 3.14f; double d1 = 3.14;
浮点型常量有两种表示形式: 十进制数形式:如:5.12 512.0f 0.512 (必须有小数点) 科学计数法形式:如:5.12e2 512E2 100E-2 2E2=200
System.out.println(2e2);//200.0
在IEEE754标准中进行了单精度浮点数(float)和双精度数浮点数(double)的定义。float有32bit,double有64bit。
它们的构成包括符号位、指数位和尾数位。
这些位的构成如下:
种类-------符号位-------------指数位----------------尾数位---- float---第31位(占1bit)---第30-23位(占8bit)----第22-0位(占23bit) double--第63位(占1bit)---第62-52位(占11bit)---第51-0位(占52bit)
取值范围主要看指数部分:
float的指数部分有8bit(2^8),由于是有符号型,所以得到对应的指数范围-128~128。
double的指数部分有11bit(2^11),由于是有符号型,所以得到对应的指数范围-1024~1024。
由于float的指数部分对应的指数范围为-128~128,所以取值范围为:
-2128到2128,约等于-3.4E38 — +3.4E38 。
float的精度为6~8位
double 精度是15~16
float 尾数可以精确到7位有效数字。很多情况下,精度很难满足需求。
double 精度是float的两倍。有效位数14
取值范围大小:byte short int long float double
//float f = 12.12345678910; float f = 12.12345678910F; //float类型必须添加F/f //编译错误,把double赋值给float,可能存在溢出 //整数部分和浮点部分总共8位,但是0除外0 //超出部分四舍五入 float d = 1234.67816729797474471F; float e = 0.678167294F; System.out.println(d);//1234.6782 System.out.println(e);//0.6781673 //整数部分和浮点部分总共16位,精确15位 double b = 12.1234567890123456789; System.out.println(b);//12.123456789012346
4.3.3 字符类型:char
char 型数据用来表示通常意义上"字符"。
字符型变量的三种表现形式: 字符变量是用单引号(‘ ’)括起来的单个字符,涵盖世界上所有书面语的字符。 例如:char c1 = 'a'; char c2 = '中'; char c3 = '9'; char c4 = '$';
Java中还允许使用转义字符‘\’来将其后的字符转变为特殊字符型常量。 例如:char c3 = ‘\n’; -- ‘\n'表示换行符 char 类型是可以进行运算的。
//浮点类型的测试 public class VaribleTest01 { public static void main(String[] args){ /* * char 型数据用来表示通常意义上的"字符"(2字节) * byte 1 Boolean 1 * short 2 char 2 * int 4 float 4 * long 8 double 8 * 字符:在Java中使用‘’来表示一个字符 * 字符可以是任意一个中文汉字、数字、字母、符号等等 * */ //表现形式一:字符常量是用单引号(‘ ’)括起来的单个字符 //注意:char能存储中文汉字原因:Java中所有字符都使用Unicode万国码编码,所以一个字符可以存储一个字母 //一个汉字,或其他书面语的一个字母 char ch1 = '1'; char ch2 = 'a'; char ch3 = '中'; char ch4 = '-'; //char类型必须存储一个字符,空格也是一个字符,无内容就不行 //char ch6 = ''; char ch7 = ' '; //字符串可以是空字符串的 String str = ""; //表现形式二:Java中允许使用转义字符‘\’来将其后的字符转变为特殊字符型常量 char ch8 = '\"'; char ch9 = '\n'; //直接使用Unicode值来表示字符型常量 //中文汉字的取值范围:[\ue400 - \u9fa8] char ch10 = '\u4567'; System.out.println(ch10);//䕧 //char类型是可以进行运算的,因为它都对应有Unicode码 char ch11 = 'a'; //a的Unicode码97 A的Unicode码65 0的Unicode码48 System.out.println(ch11 + 19); //97+19=116 } }
4.3.4 布尔类型:boolean
boolean 类型适于逻辑运算,一般用于程序流程控制:
if条件控制语句; while循环控制语句; do-while循环控制语句; for循环控制语句;
boolean类型数据只允许取值true和false,不可以0或非 0 的整数替代true和false,这点和JS、C语言不同。 boolean占一个字节
//布尔类型的测试 public class VaribleTest01 { public static void main(String[] args) { boolean a1 = true; boolean a2 = false; //boolean a3 = null; 值不能这样写 boolean isMarried = true; if (isMarried) { System.out.println("你就不能参与我们的单身周末了"); }else{ System.out.println("可以放飞自我了"); } boolean a4; System.out.println(a4 = a1);//true System.out.println(a4 = a2);//false }}
//字符串类型的测试 public class VaribleTest01 { public static void main(String[] args) { /* *字符串不是基本数据类型,而是引用数据类型 * 字符串必须使用"" * 一个字符串可以串接另一个字符串,也可以直接串接其他类型的数据。(字符串串联接) * 任意数据类型都可以和字符串进行+运算(连接运算,字符串拼接),得到的都是一个新字符串 * */ String str = "Hello"; System.out.println(str + 100); //Hello100 System.out.println(str + 100 +50); //Hello10050 System.out.println(100 + 50 + str); //150Hello System.out.println(str + 100); //Hello100 System.out.println(str + (100 + 50)); //Hello150 //把数值类型转换为字符串 int num = 100; String numStr = num + ""; System.out.println(numStr);//"100" //扩展:怎么把字符串转换为数值 把“100”转换为100 int num1 = Integer.parseInt(numStr); System.out.println(num1);//100 }}
4.3.5 基本数据类型转换
4.3.5.1 自动类型转换
自动类型转换:容量小的类型自动转换为容量大的数据类型。数据类型按容量大小排序为:
将一种类型的变量赋给另一种类型的变量时,只要满足以下条件,就会发生自动类型转换。
两种类型兼容; 目标类型大于源类型;
有多种类型的数据混合运算时,系统首先自动将所有数据转换成容量最大的那种数据类型,然后再进行计算。
运算时:byte,short,char之间不会相互转换,他们三者在计算时首先转换为int类型。
当把任何基本类型的值和字符串值进行连接运算时(+),基本类型的值将自动转化为字符串类型。
//基本数据类型的测试 public class VaribleTest01 { public static void main(String[] args) { /* * 基本数据类型转换分为两种: * 自动类型转换:容量小的类型会自动转换为容量大的类型 * 强制类型转换: * 基本数据类型转换指的是7种类型之间的转换规则,不包含boolean * * 1、容量小的类型赋值给容量大的类型,会发生自动类型转换 * 容量从小到大分别是:byte——short/char——int——long——float——double * 注意:这里的容量大小指的是表示数的范围的大小,比如float容量要大于long的容量 * */ byte b1 = 102; short s1 = 3200; int i1 = b1;//i1=102 long l1 = s1;//l1=3200 float f1 = l1;//f1=3200 char ch1 = 'a'; System.out.println(ch1);//a i1 = ch1; System.out.println(i1);//97 // 2、当容量小的类型和容量大的类型进行运算的时候,会自动转换为大类型 //注意:byte/short/char在进行运算的时候,直接转换为int byte b2 = 102; short s2 = 666; int i2 = 67; double d2 = 54.2; int sum1 = i2 + b2;//int类型 = int类型 + byte类型 double sum2 = i2 + d2;//double类型 = int类型 + double类型 int sum3 = b2 + s2;//int类型 = byte类型 + short类型 }}
4.3.5.2 强制类型转换
自动类型转换(隐式转换)的逆过程,将容量大的数据类型转换为容量小的数据类型。使用时要加上强制转换符(()),但可能造成精度降低或溢出,格外要注意。
通常,字符串不能直接转换为基本类型,但通过基本类型对应的包装类则可以实现把字符串转换成基本类型。如: String a = “43”; int i = Integer.parseInt(a);
boolean类型不可以转换为其它的数据类型。
//强制类型转换 public class VaribleTest01 { public static void main(String[] args) { double d1 = 666.73; System.out.println(d1);//double 输出值为:666.73 //int i1 = d1;//因为666.73在编译的时候,就会认为double类型的范围远大于int,会存在溢出问题,编译失败 int i1 = (int)d1; //因为666.73在int的取值范围以内,不存在精度溢出问题 System.out.println(i1);//666 int i2 = 128; byte b2 = (byte)i2;//128超出byte取值范围,溢出 System.out.println(b2);//-128 /* * byte * -128~127 * 10000000 * 01111111 * 127 + 1 —— 01111111 + 1 = 10000000 —— -128 * */ }}
4.3.5.3 类型转换对于表达式
如果一个操作数为 long 型,则整个表达式提升为 long 型 如果一个操作数为 float 型,则整个表达式提升为 float 型 如果一个操作数为 double 型,则整个表达式提升为 double 型 在整个运算表达式中找到最大的类型,这个类型及是表达式运算后的类型
4.4 局部变量作用域和生命周期
前面我们说变量要先定义,后使用,但也不是在变量定义后的语句一直都能使用前面定义的变量。我们可以用大括号将多个语句包起来形成一个复合语句,变量只能在定义它的复合语句中使用,即:变量的作用范围从被定义开始到距离其最近的“}”处结束。 变量可以在代码块或方法中声明 块以左大括号开始,以右大括号结束 块用来定义作用域 每次创建一个新块后,就会创建一个新的作用域 变量的作用域是一个作用的范围,每个变量都有自己的作用域 变量的生存期是指变量的生存周期 所谓生命周期,也有说法叫做作用域。是指常量和变量都有自己固定的生效范围,一旦在这个范围之外将失去效用。生命周期一般以区间作为界限,即{}
五、进制
进制也就是进位计数制,是人为定义的带进位的计数方法。 对于任何一种进制---X进制,就表示每一位置上的数运算时都是逢X进一位。
十进制是逢十进一,十六进制是逢十六进一,二进制就是逢二进一,以此类推,x进制就是逢x进位。.比如在运算中常见的进制有十进制、二进制、八进制、十六进制,在日常生活中星期是七进制,秒是60进制,月是12进制等等。
二进制是计算技术中广泛采用的一种数制。二进制数据是用0和1两个数码来表示的数。它的基数为2,进位规则是“逢二进一”,借位规则是“借一当二”,由18世纪德国数理哲学大师莱布尼兹发现。当前的计算机系统使用的基本上是二进制系统,数据在计算机中主要是以补码的形式存储的。计算机中的二进制则是一个非常微小的开关,用“开”来表示1,“关”来表示0。
进制 英文 范围 前缀 后缀 二进制 Binary 0-1 0b B 八进制 Octal 0-7 0 O 十进制 Decimal 0-9 \ D 十六进制 Hexadecimal 0-9, A-F 0x H
5.1 二进制和十进制之间的转换
5.1.1 十进制转二进制
方法为:十进制数除2取余法,即十进制数除2,余数为权位上的数,得到的商值继续除2,依此步骤继续向下运算直到商为0为止。 (具体用法如下图)
5.1.2 二进制转十进制
方法为:二进制转换成十进制,需要二进制的每一位的数值乘以相应的2的幂次方,然后相加。
基数: X进制的基数是X 系数:每一位上面的数值 权:每一位上基数的幂(乘方)
公式:系数乘以基数的权次幂
(具体用法如下图)
5.2 二进制与八进制之间的转换
5.2.1 二进制转八进制
方法为:3位二进制数按权展开相加得到1位八进制数。(注意事项,3位二进制转成八进制是从右到左开始转换,不足时补0)。
(具体用法如下图)
5.2.2 八进制转成二进制
方法为:八进制数通过除2取余法,得到二进制数,对每个八进制为3个二进制,不足时在最左边补零。
(具体用法如下图)
5.3 二进制与十六进制之间的转换
5.3.1 二进制转十六进制
方法为:与二进制转八进制方法近似,八进制是取三合一,十六进制是取四合一。(注意事项,4位二进制转成十六进制是从右到左开始转换,不足时补0)。
(具体用法如下图)
5.3.2 十六进制转二进制
方法为:十六进制数通过除2取余法,得到二进制数,对每个十六进制为4个二进制,不足时在最左边补零。 (具体用法如下图)
5.4 十进制与八进制与十六进制之间的转换
5.4.1 十进制转八进制或者十六进制有两种方法
第一:间接法—把十进制转成二进制,然后再由二进制转成八进制或者十六进制。这里不再做图片用法解释。
第二:直接法—把十进制转八进制或者十六进制按照除8或者16取余,直到商为0为止。
(具体用法如下图)
5.4.2 八进制或者十六进制转成十进制
方法为:把八进制、十六进制数按权展开、相加即得十进制数。
(具体用法如下图)
5.5 十六进制与八进制之间的转换
八进制与十六进制之间的转换有两种方法
第一种:他们之间的转换可以先转成二进制然后再相互转换。
第二种:他们之间的转换可以先转成十进制然后再相互转换。
System.out.println(0b101);//二进制:5 (0b开头的) System.out.println(011);//八进制:9 (0开头的) System.out.println(11);//十进制:11 System.out.println(0x11C);//十六进制:284 (0x开头的)
//进制的转换形式和转换规则 public class VaribleTest01 { public static void main(String[] args) { /* * 十六进制(hex),以0x或0X开头表示。此处的A-F不区分大小写 * 无论是哪种进制,在输出的时候,都会转成十进制 * */ int num1 = 0b11;//Binnary 二进制 以数字0b或0B开头 System.out.println(num1);//3 int num2 = 011;//octal 八进制 以数字0开头 System.out.println(num2);//9 int num3 = 11; System.out.println(num3);//11 int num4 = 0x11;//hex System.out.println(num4);//17 }}
六、真值、机器数、原码、反码、补码
面试题:什么是原码、反码、补码?为何要使用它?
机器数
一个数在计算机中的二进制表示形式, 叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1.
比如,十进制中的数 +3 ,计算机字长为8位,转换成二进制就是00000011。如果是 -3 ,就是 10000011 。那么,这里的 00000011 和 10000011 就是机器数。
真值
因为第一位是符号位,所以机器数的形式值就不等于真正的数值。例如上面的有符号数 10000011,其最高位1代表负,其真正数值是 -3 而不是形式值131(10000011转换成十进制等于131)。所以,为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值。
例:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –000 0001 = –1
原码是什么?
原码就是早期用来表示数字的一种方式: 一个正数,转换为二进制位就是这个正数的原码。
负数的绝对值转换成二进制位然后在高位补1就是这个负数的原码
举例说明:
比如如果是8位二进制:
[+1]原 = 0000 0001
[-1]原 = 1000 0001
第一位是符号位. 因为第一位是符号位, 所以8位二进制数的取值范围就是:
[1111 1111 , 0111 1111],即:
[-127 , 127]
原码是人脑最容易理解和计算的表示方式.
但是原码有几个缺点,零分两种 +0 和 -0 。很奇怪是吧!还有,在进行不同符号的加法运算或者同符号的减法运算的时候,不能直接判断出结果的正负。你需要将两个值的绝对值进行比较,然后进行加减操作 ,最后符号位由绝对值大的决定。于是反码就产生了。
反码是什么 ?
反码的表示方法是:正数的反码是其本身;负数的反码是在其原码的基础上, 符号位不变,其余各个位取反。
举例说明:
[+1] = [00000001]原 = [00000001]反
[-1] = [10000001]原 = [11111110]反
可见如果一个反码表示的是负数, 人脑无法直观的看出来它的数值. 通常要将其转换成原码再计算。
补码是什么?
补码的表示方法是:正数的补码就是其本身;负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)
还是举例说明:
[+1] = [00000001]原 = [00000001]反 = [00000001]补
[-1] = [10000001]原 = [11111110]反 = [11111111]补
对于负数, 补码表示方式也是人脑无法直观看出其数值的. 通常也需要转换成原码在计算其数值.
为何要使用原码, 反码和补码
在开始深入学习前, 我的学习建议是先”死记硬背”上面的原码, 反码和补码的表示方式以及计算方法. 现在我们知道了计算机可以有三种编码方式表示一个数. 对于正数因为三种编码方式的结果都相同: [+1] = [00000001]原 = [00000001]反 = [00000001]补 所以不需要过多解释. 但是对于负数: [-1] = [10000001]原 = [11111110]反 = [11111111]补 可见原码, 反码和补码是完全不同的. 既然原码才是被人脑直接识别并用于计算表示方式, 为何还会有反码和补码呢? 首先, 因为人脑可以知道第一位是符号位, 在计算的时候我们会根据符号位, 选择对真值区域的加减. (真值的概念在本文最开头). 但是对于计算机, 加减乘除已经是最基础的运算, 要设计的尽量简单. 计算机辨别”符号位”显然会让计算机的基础电路设计变得十分复杂! 于是人们想出了将符号位也参与运算的方法. 我们知道, 根据运算法则减去一个正数等于加上一个负数, 即: 1-1 = 1 + (-1) = 0 , 所以机器可以只有加法而没有减法, 这样计算机运算的设计就更简单了. 于是人们开始探索 将符号位参与运算, 并且只保留加法的方法. 首先来看原码。计算十进制的表达式: 1-1=0 1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2 如果用原码表示, 让符号位也参与计算, 显然对于减法来说, 结果是不正确的.这也就是为何计算机内部不使用原码表示一个数. 为了解决原码做减法的问题, 出现了反码。计算十进制的表达式: 1-1=0 1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0 发现用反码计算减法, 结果的真值部分是正确的. 而唯一的问题其实就出现在”0”这个特殊的数值上. 虽然人们理解上+0和-0是一样的, 但是0带符号是没有任何意义的. 而且会有[0000 0000]原和[1000 0000]原两个编码表示0. 于是补码的出现, 解决了0的符号以及两个编码的问题: 1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]补 + [1111 1111]补 = [0000 0000]补=[0000 0000]原 这样0用[0000 0000]表示, 而以前出现问题的-0则不存在了.而且可以用[1000 0000]表示-128: (-1) + (-127) = [1000 0001]原 + [1111 1111]原 = [1111 1111]补 + [1000 0001]补 = [1000 0000]补 -1-127的结果应该是-128, 在用补码运算的结果中, [1000 0000]补 就是-128. 但是注意因为实际上是使用以前的-0的补码来表示-128, 所以-128并没有原码和反码表示.(对-128的补码表示[1000 0000]补算出来的原码是[0000 0000]原, 这是不正确的) 使用补码, 不仅仅修复了0的符号以及存在两个编码的问题, 而且还能够多表示一个最低数. 这就是为什么8位二进制, 使用原码或反码表示的范围为[-127, +127], 而使用补码表示的范围为[-128, 127]. 因为机器使用补码, 所以对于编程中常用到的32位int类型, 可以表示范围是: [-231, 231-1] 因为第一位表示的是符号位.而使用补码表示时又可以多保存一个最小值.
/* * 真值 +3 -3 * 原码 0000 0011 1000 0011 * 反码 0000 0011 1111 1100 * 补码 0000 0011 1111 1101 * * 正数的原码、反码、补码都是二进制的表现形式 * 负数的原码是负数的绝对值二进制然后高位补1; * 负数的反码是符号位不变,其他各个位取反; * 负数的补码是在反码的基础上+1; * */
总结
正数的反码和补码都与原码相同。 负数的反码为对该数的原码除符号位外各位取反。 负数的补码为对该数的原码除符号位外各位取反,然后在最后一位加1 对于负数原码转补码 符号位不变,然后按位取反+1; 对于负数补转原码 符号位不变,然后按位取反+1;
各自的优缺点:
原码最好理解了,但是加减法不够方便,还有两个零。 反码稍微困难一些,解决了加减法的问题,但还是有有个零 补码理解困难,其他就没什么缺点了
七、运算符
Java提供了一组丰富的操作符来操作变量。 我们可以将所有Java运算符划分为以下几个分类
算术运算符 关系运算符,比较运算符 按位运算符,了解 逻辑运算符 赋值运算符 其他运算符
7.1. 算术运算符
算术运算符在数学表达式中的使用方式与在代数中使用的方式相同。下表列出了算术运算符的使用示例 - 假设整数类型变量A的值为:10,变量B的值为:20,则
注: 算数运算符一般是用来做数值运算的(char类型可以参与到数值运算);但是在java里面,字符串可以和任意数据类型做+运算,都是字符串的拼接。
//++和--的测试 /* * 面试题:++(--)在前和在后的区别? * 如果++(--)不参与运算(就是直接输出结果,调用也不行),那么在前和在后没有区别; * ++(--)在前,先自增(自减)计算(一条单独的语句),然后再取值 * ++(--)在后,先自增(自减)计算,然后再取值 * 在自身的基础上-1 * a ++ 相当于 a = a + 1; * */ public class VaribleTest01 { public static void main(String args[]) { int a = 10; int b = 20; int c = 25; int d = 25; int num1 = 10; int num2 = 20; int k1 = 10; int k2 = 20; num1 ++;//一条单独的语句 ++ num2;//一条单独的语句 //直接得到结果 System.out.println(num1);//11 System.out.println(num2);//21 //参与调用 System.out.println("k1++得到结果"+ k1++);//10 System.out.println("k1++得到结果"+ ++k2);//21 //参与运算 //在输入语句输出的时候,先取a的值10放到控制台上,在+1变成11 System.out.println("a++ = " + (a++) );//a ++ = 10 System.out.println(a);//11 //在输入语句输出的时候,先取a的值11放到控制台上,在-1变成10 System.out.println("a-- = " + (a--) );//11 System.out.println(a);//10 // 对比 d++ 和 ++d 有什么区别 System.out.println("d++ = " + (d++) );//d ++ = 25,取值之后,d = 26 System.out.println(d);//26 System.out.println("++d = " + (++d) );//++ d = 27,取值之后,d = 27 System.out.println(d);//27 //注意事项 short s = 10; //s = s + 1;//编译失败,short类型和int类型进行运算,得到的是int类型 改变方法如下: //方法一: 需要强转 s =(short) (s + 1); //方法二; 等价与【s = s + 1;】= 【s += 1;】自增运算符不会改变数据类型 //++ \ += 都是内置运算符,不会改变数据类型 s++; //三种对数值进行+1运算的写法 short n1 = 10; short n2 = 10; short n3 = 10; //写法1 n1 = (short) (n1 + 1); //写法2(推荐) n2++; //写法3 n3 += 1; System.out.println(n1);//11 System.out.println(n2);//11 System.out.println(n3);//11 //注意事项: byte n4 = 127; n4++; System.out.println(n4);//-128 } }
执行上面示例代码,得到以下结果:
a + b = 30 a - b = -10 a * b = 200 b / a = 2 b % a = 0 c % a = 5 a++ = 10 b-- = 11 d++ = 25 ++d = 27
public class VaribleTest01 { /* * 对于除号“/”,它的整数除法和小数除是有区别的: * 1、两个整数类型做运算,得到的肯定是整数类型,只有浮点数参与运算了,才得到的是小数 * 2、0不能作为除数,但是和浮点类型做运算可以作为除数 * */ public static void main(String args[]) { int num1 = 12; int num2 =5; int x = num1 / num2; double y = num1 / num2; System.out.println(x);//2 System.out.println(y);//2.0 double num3 =5.0; System.out.println("num1 / num3 = " + num1 / num3 );//2.4 2.4属于double类型 System.out.println("num1 / num2 = " + (double)(num1 / num2) );//2.0 System.out.println("num1 / num3 = " + num1 /(double) num2 );//2.4 //0不能作为除数,但是和浮点类型做运算可以作为除数 //编译正常,运行报错 //System.out.println("num1 / 0 = " + num1 / 0 ); //Exception in thread "main" java.lang.ArithmeticException: / by zero //编译正常,运行正常 Infinity 无穷大 double result1 = 12.0 / 0; double result2 = 12 / 0.0; System.out.println(result1);//Infinity System.out.println(result2);//Infinity //0能不能作为除数? //0在和整数类型进行除法运算的时候,不能作为除数; //0在和浮点类型进行除法运算的时候,可以作为除数,得到的结果是Infinity } }
/* * 取模(取余)运算的注意事项 * */ public class VaribleTest01 { public static void main(String args[]) { /* * 取余结果的符号与被模数的符号相同 * 12 / 5 5是除数,12是被除数 * 12 % 5 5是模数,12是被模数 * */ int a1 = 12; int a2 = 5; System.out.println("a1 % a2 = " + (a1 % a2));//正2 int a3 = -12; int a4 = 5; System.out.println("a3 % a4 = " + (a3 % a4));//负2 int a5 = 12; int a6 = -5; System.out.println("a5 % a6 = " + (a5 % a6));//正2 int a7 = -12; int a8 = -5; System.out.println("a7 % a8 = " + (a7 % a8));//负2 } }
7.2. 关系运算符
Java语言支持以下关系运算符。假设变量A的值是10,变量B的值是20,则
注:关系运算符的返回值都是boolean类型。一般结合流程控制语句使用
Java关系运算符示例代码如下 -
public class VaribleTest01 { public static void main(String args[]) { int a = 10; int b = 20; //比较运算符的结果是boolean类型 System.out.println("a == b = " + (a == b) );//a == b = false System.out.println("a != b = " + (a != b) );//a != b = true System.out.println("a > b = " + (a > b) );//a > b = false System.out.println("a < b = " + (a < b) );//a < b = true System.out.println("b >= a = " + (b >= a) );//b >= a = true System.out.println("b <= a = " + (b <= a) );//b <= a = false /* * 区分好==和=的区别: * */ boolean b1 = false; if(b1 == true){ //false == true 结果比较为false System.out.println("结果为真"); }else{ System.out.println("结果为假");//输出 } boolean b2 = false; if(b2 = true){ //把true赋值给b2 System.out.println("结果为真"); }else{ System.out.println("结果为假");//输出 } } }
7.3 按位运算符
Java定义了几个按位运算符,可以应用于整数类型, 如:long,int,short,char和byte。按位运算符处理位并执行逐位运算。 假设a = 60且b = 13; 采用二进制格式,它们将如下 -
a = 0011 1100 b = 0000 1101 ----------------- // 1.参加运算的两个数据,按照二进制进行按位与的运算。 // 运算规则:0&0=0; 0&1=0; 1&0=0; 1&1=1; // 即:两位同时为“1”,结果才为“1”,否则为0。 a&b = 0000 1100 // 2.参加运算的两个对象,按二进制位进行“或”运算。 // 运算规则:0|0=0; 0|1=1; 1|0=1; 1|1=1; // 即 :参加运算的两个对象只要有一个为1,其值为1。 a|b = 0011 1101 // 3.参加运算的两个数据,按二进制位进行“异或”运算。 // 运算规则:0^0=0; 0^1=1; 1^0=1; 1^1=0; // 即:参加运算的两个对象,如果两个相应位为“异”(值不同),则该位结果为1,否则为 0。 a^b = 0011 0001 ~a = 1100 0011
下面的表中列出了按位运算符,假设整数变量A=60,变量B=13,那么 -
&和 |或 ^异或
三种移位符号
>>
是带符号右移,若左操作数是正数,则高位补“0”,若左操作数是负数,则高位补“1”.
<<
将左操作数向左边移动,并且在低位补0.
>>>
是无符号右移,无论左操作数是正数还是负数,在高位都补“0”
如果是对负数移位,则是对补码移位
三种移位符号作用的左操作数有五种:long,int,short,byte,char
但是在作用不同的操作数类型时,其具体过程不同, 遵循一下几个原则:
-
int移位时,左边的操作数是32位的,此时的移位符号作用在32位bit上。如:
1 >> 3
, 是将00000000 00000000 00000000 00000001这32位向右边移动3位。 -
long 移位时,左边的操作数是64位的,此时移位符号作用在64位bit上。如:
1L >> 3
。 -
short, byte,char 在移位之前首先将数据转换为int,然后再移位,此时移位符号作用在32为bit上。如:
(byte)0xff >>> 7
, 是将11111111 11111111 11111111 11111111向右边移动7位,得到00000001 11111111 11111111 11111111
有1,2可知,当左操作数是long时,移位之后得到的类型是long,当左操作数是其它四中类型时,移位之后得到的类型是int,所以如果做操作数是byte,char,short 时,你用 >>=
,>>>=
, <<=
其实是将得到的int 做低位截取得到的数值。
byte a = 100; a>>=2; //a = a>>2;
public class Test { public static void main(String args[]) { int a = 60; /* 60 = 0011 1100 */ int b = 13; /* 13 = 0000 1101 */ int c = 0; c = a & b; /* 12 = 0000 1100 */ System.out.println("a & b = " + c ); c = a | b; /* 61 = 0011 1101 */ System.out.println("a | b = " + c ); c = a ^ b; /* 49 = 0011 0001 */ System.out.println("a ^ b = " + c ); c = ~a; /*-61 = 1100 0011 */ System.out.println("~a = " + c ); c = a << 2; /* 240 = 1111 0000 */ System.out.println("a << 2 = " + c ); c = a >> 2; /* 15 = 1111 */ System.out.println("a >> 2 = " + c ); c = a >>> 2; /* 15 = 0000 1111 */ System.out.println("a >>> 2 = " + c ); } }
执行上面示例代码,得到以下结果:
a & b = 12 a | b = 61 a ^ b = 49 ~a = -61 a << 2 = 240 a >> 2 = 15 a >>> 2 = 15
public class VaribleTest01 { public static void main(String args[]) { //练习:交换两个变量的值 int num1 = 10; int num2 = 20; System.out.println("num1 = " + num1 + ",num2 = " + num2 ); //第一种:定义临时变量 //最简单的,推荐使用的 // int temp = num1;//temp = 10 // num1 = num2;//num1 = 20 // num2 = temp;//num2 = 10 // System.out.println("num1 = " + num1 + ",num2 = " + num2 ); //第二种:数值运算符 // num1 = num1 + num2; // num2 = num1 - num2; // num1 = num1 - num2; // System.out.println("num1 = " + num1 + ",num2 = " + num2 ); //第三种:按位运算符 //num1 = 10 二进制:0000 1010 //num2 = 20 二进制:0001 0100 num1 = num1 ^ num2;//0001 1110 30 num2 = num1 ^ num2;//0000 1010 10 num1 = num1 ^ num2;//0001 0100 20 System.out.println("num1 = " + num1 + ",num2 = " + num2 ); } }
7.4 逻辑运算符
下表列出了逻辑运算符 - 假设布尔变量A的值为:true,变量B 的值为:false,则 - 以下简单的示例程序演示了逻辑运算符。 将以下Java程序复制并粘贴到Test.java文件中,然后编译并运行该程序 -
public class Test { public static void main(String args[]) { boolean a = true; boolean b = false; System.out.println("a && b = " + (a&&b)); System.out.println("a || b = " + (a||b) ); System.out.println("!(a && b) = " + !(a && b)); } }
执行上面示例代码,得到以下结果:
a && b = false a || b = true !(a && b) = true 注意:&&与||的短路问题 &与|也可以用于逻辑运算,但是不存在短路情况。
/* * 逻辑运算符测试 * */ public class VaribleTest01 { public static void main(String args[]) { /* * &和&&的区别? * &和&&都是作与运算符,结果都是一致的 * &是按位与运算,&&是逻辑与运算 * &不具备短路,&&具备短路,如果第一个表达式的结果为false,则不在执行第二个; * 公式:两者都为真,才为真,否则为假 * * |和||的区别? * |和||都是作或运算符,结果都是一致的 * |是按位或运算,||是逻辑或运算 * |不具备短路,||具备短路,如果第一个表达式的结果为true,则不在执行第二个; * 公式:只要有一个为真,结果就为真,否则为假 * * 良好的编程习惯:运算符两侧为空格 * IDEA的格式化代码快捷键;Ctrl+Alt+L * * 结论:运算符的优先级低于 + * */ System.out.println("&和 &&的测试"); System.out.println((true & true)+"\t"+(true & false)+"\t"+(false & false)+"\t"); System.out.println((true && true)+"\t"+(true && false)+"\t"+(false && false)+"\t"); System.out.println("|和 ||的测试"); System.out.println((true | true)+"\t"+(true | false)+"\t"+(false | false)+"\t"); System.out.println((true || true)+"\t"+(true || false)+"\t"+(false || false)+"\t"); int a = 10; int b = 10; boolean b1 = 5 > 3 & a++ > 10;//输出控制台10 a=11 boolean b2 = 5 > 3 && b++ > 10;//输出控制台10 b=11 System.out.println(b1 +"\t" + b2 +"\t"+ a +"\t" + b); boolean b3 = 5 < 3 & a++ > 10;//输出控制台11 a变为12 boolean b4 = 5 < 3 && b++ > 10;//b变为11 System.out.println(b3 +"\t" + b3 +"\t"+ a +"\t" + b); } }
7.5. 赋值运算符
以下是Java语言支持的赋值运算符;
/* *运算符:用来进行运算的符号 * 表达式:有运算符连接起来,符合java运算规则的式子 * 操作数:运算符两侧的值或变量就是操作数 * */ public class VaribleTest01 { public static void main(String args[]) { // = 简单的赋值运算符,将右边操作数的值赋给左边操作数 //当“=”两侧数据类型不一致时,可以使用自动类型转换或强制类型转换原则进行处理 //支持连续赋值 int num1 = 100; long num2 = num1;//num1是int类型,num2是long类型,发生了自动类型转换 byte num3 = (byte)num1;//num1是int类型,num3是byte类型,必须强转 //String str = num1;//编译失败 //变量的另一种写法 但是有些规则不支持这种写法,少数 // int a; // int b; // int c; int a,b,c;//一次性声明3个int类型变量 int x,y = 10,z;//一次性声明3个int类型的变量,并且给y赋值 } }
以下程序是一个演示赋值运算符的简单示例。 将以下Java程序复制并粘贴到Test.java文件中。 编译并运行此程序 -
public class Test { public static void main(String args[]) { int a = 10; int b = 20; int c = 0; c = a + b; System.out.println("c = a + b = " + c ); c += a ; System.out.println("c += a = " + c ); c -= a ; System.out.println("c -= a = " + c ); c *= a ; System.out.println("c *= a = " + c ); a = 10; c = 15; c /= a ; System.out.println("c /= a = " + c ); a = 10; c = 15; c %= a ; System.out.println("c %= a = " + c ); c <<= 2 ; System.out.println("c <<= 2 = " + c ); c >>= 2 ; System.out.println("c >>= 2 = " + c ); c >>= 2 ; System.out.println("c >>= 2 = " + c ); c &= a ; System.out.println("c &= a = " + c ); c ^= a ; System.out.println("c ^= a = " + c ); c |= a ; System.out.println("c |= a = " + c ); } }
执行上面示例代码,得到以下结果 -
c = a + b = 30 c += a = 40 c -= a = 30 c *= a = 300 c /= a = 1 c %= a = 5 c <<= 2 = 20 c >>= 2 = 5 c >>= 2 = 1 c &= a = 0 c ^= a = 10 c |= a = 10
7.6 其它运算符
Java语言支持的其他运算符很少。
7.6.1. 三目运算符 (?:)
三目运算符也称为三元运算符。 此运算符由三个操作数组成,用于计算布尔表达式。 运算符的目标是确定应将哪个值赋给变量。 运算符写成 -
variable x = (expression) ? value if true : value if false
下面是一段示例代码:
public class Test { public static void main(String args[]) { int a, b; a = 10; b = (a == 1) ? 20: 30; System.out.println( "Value of b is : " + b ); b = (a == 10) ? 20: 30; System.out.println( "Value of b is : " + b ); } }
执行上面示例代码,得到以下结果 -
Value of b is : 30 Value of b is : 20
7.6.2. instanceof运算符
此运算符仅用于对象引用变量。 运算符检查对象是否属于特定类型(类类型或接口类型)。 instanceof运算符写成 -
( Object reference variable ) instanceof (class/interface type)
如果操作符左侧的变量引用的对象是右侧的类/接口类型,则结果为真。 以下是一个例子 -
public class Test { public static void main(String args[]) { String name = "Kobe"; // 当 name 的类型是 String 时,则返回为:true boolean result = name instanceof String; System.out.println( result ); } }
执行上面示例代码,得到以下结果:
true
如果要比较的对象与右侧类型兼容,则此运算符仍将返回true。 以下是另一个例子 -
class Vehicle {} public class Car extends Vehicle { public static void main(String args[]) { Vehicle a = new Car(); boolean result = a instanceof Car; System.out.println( result ); } }
执行上在示例代码,得到以下结果:
true
7.7 运算符的优先级
当多个运算符出现在一个表达式中,谁先谁后呢?这取决于优先级。小括号的优先级是最高的。下表中具有最高优先级的运算符在的表的最上面,最低优先级的在表的底部。
第一优先级: () [] .
第二优先级: 算数运算符
第三优先级: 关系运算符
第四优先级: 逻辑运算符
第五优先级:赋值运算符
八、流程控制语句
流程控制语句是用来控制程序中各语句执行顺序的语句,可以把语句组合成能完成一定功能的小逻辑模块。其流程控制方式有:顺序结构、分支结构和循环结构。
8.1 顺序结构
从上到下依次执行
package Test3; public class OrderDemo { public static void main(String[] args) { System.out.println(1); System.out.println(2); System.out.println(3); } }
8.2 分支结构
8.2.1 if单分支语句
语法: if(条件表达式){ 语句块; } 解释: 条件表达式结果为boolean类型,当表达式结果为true,则执行语句块;否则什么都不执行! 当语句块只有1句代码时,可以省略大括号.建议不要省略
package Test3; public class IfDemo1 { public static void main(String[] args) { int a = 10; int b = 10; if(a>b){ System.out.println("hello"); } System.out.println("..........."); if(a==b){ System.out.println("hello"); } } }
示例:
张浩Java成绩大于98分,而且音乐成绩大于80分,老师奖励他;或者Java成绩等于100分,音乐成绩大于70分,老师也可以奖励他.
public class GetPrize2 { public static void main(String[] args) { int score1 = 100; // 张浩的Java成绩 int score2 = 72; // 张浩的音乐成绩 if ( ( score1 >98&& score2 > 80 )|| ( score1 == 100 && score2 > 70 ) ){ System.out.println("老师说:不错,奖励一个MP4!"); } } }
8.2.2 if双分支语句
语法: if(条件表达式){ 语句块A; }else{ 语句块B; } 解释: 条件表达式结果为boolean类型,当表达式结果为true,则执行语句块A;否则执行语句块B!
package Test3; public class IfDemo2 { public static void main(String[] args) { int a = 10; int b = 10; if(a==b){ System.out.println("hello"); }else{ System.out.println("你好"); } System.out.println("............"); if(a>b){ System.out.println("hello"); }else{ System.out.println("你好"); } } }
示例:
如果张浩Java考试成绩大于98分,老师就奖励他一个MP4,否则老师就罚他进行编码。
public class SimpleIf2 { public static void main(String[] args) { int score = 91; // 张浩的Java成绩 if (score > 98) { System.out.println("老师说:不错,奖励一个MP4!"); } else { System.out.println("老师说:惩罚进行编码!"); } } }
8.2.3 if多分支语句
语法: if(条件表达式A){ 语句块A; }else if(条件表达式B){ 语句块B; }... else if(条件表达式N){ 语句块N; }else{ 语句块N+1 } 解释: 所有的条件表达式结果都是boolean类型。 如果条件表达式A结果为true,则执行语句块A,否则去判断条件表达式B; 如果条件表达式B结果为true,则执行语句块B,否则去判断条件表达式C; .... 如果所有的条件表达式结果都为false,则执行语句块N+1
为什么使用多重if选择结构?
问题: 1、对学员的结业考试成绩评测 成绩>=90 :优秀 成绩>=80 :良好 成绩>=60 :中等 成绩<60 :差 分析:将成绩分成几个连续区间判断。使用单个if选择结构无法完成,使用多个if选择结构很麻烦 ,所以要使用多重if选择结构。
int score = 70; //考试成绩 if ( score >= 90 ) { System.out.println("优秀"); } else if (score >= 80 ) { System.out.println("良好"); } else if (score >= 60 ) { System.out.println("中等"); } else { System.out.println("差"); }
练习:我想买车,买什么车决定于我在银行有多少存款 如果我的存款超过500万,我就买凯迪拉克 否则,如果我的存款超过100万,我就买帕萨特 否则,如果我的存款超过50万,我就买依兰特 否则,如果我的存款超过10万,我就买奥托 否则,我买捷安特
int money = 52; // 我的存款,单位:万元 if (money >= 500) { System.out.println("太好了,我可以买凯迪拉克"); } else if (money >= 100) { System.out.println("不错,我可以买辆帕萨特"); } else if (money >= 50) { System.out.println("我可以买辆依兰特"); } else if (money >= 10) { System.out.println("至少我可以买个奥托"); } else { System.out.println("看来,我只能买个捷安特了"); }
8.2.4 嵌套if
为什么使用嵌套if?
问题: 学校举行运动会,百米赛跑跑入10秒内的学生有资格进决赛,根据性别分别进入男子组和女子组 分析: 要判断是否能够进入决赛 在确定进入决赛的情况下,还要判断是进入男子组,还是进入女子组 解决: 使用嵌套if选择结构
语法: if(条件1) { if(条件2) { 代码块1 } else { 代码块2 } } else { 代码块3 }
if(score<=10){ if(gender.equals("男")){ System.out.println("进入男子组决赛!"); }else if(gender.equals("女")){ System.out.println("进入女子组决赛!"); } }else{ System.out.println("淘汰!"); }
注: 为了使 if 结构更加清晰、避免执行错误,应该把每个 if 或 else 包含的代码块都用大括号括起来 相匹配的一对 if 和 else 应该左对齐 内层的 if 结构相对于外层的 if 结构要有一定的缩进
8.2.5 switch语句
语法: switch(表达式){ case 值1: 语句块1; break; ..... case 值N: 语句块N; break; default: 语句块default; } 解释: 表达式在这里其实是一个值:但是必须是byte,short,int,char,String其中的一种。 break不是语法中固定的,可以加也可以不加,但是如果为了打断switch的贯穿性,需要结合break使用。 default块顺序可以变动,但要注意其执行顺序。通常,default块放在末尾,也可以省略;但是如果default放在前面,推荐添加break; case的顺序无所谓。 程序会使用表达式值从上到下跟case后面的值进行比较,如果相等,则执行对应的语句块,否则继续向后对比; 如果都不想等,则执行default。
package Test3; import java.util.Scanner; public class SwitchDemo { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("只能输入1,2,3:"); int a = sc.nextInt(); switch(a){ case 1: System.out.println("你"); break; case 2: System.out.println("好"); break; case 3: System.out.println("呀"); break; default: System.out.println("输入错误,请重新输入"); break; } } }
案例:
韩嫣参加计算机编程大赛 如果获得第一名,将参加麻省理工大学组织的1个月夏令营 如果获得第二名,将奖励惠普笔记本电脑一部 如果获得第三名,将奖励移动硬盘一个 否则,不给任何奖励 该问题属于等值判断 解决方法: 使用多重if选择结构实现 使用switch选择结构解决
int mingCi = 1; switch (mingCi) { case 1: System.out.println("参加麻省理工大学组织的1个月夏令营"); break; case 2: System.out.println("奖励惠普笔记本电脑一部"); break; case 3: System.out.println("奖励移动硬盘一个"); break; default: System.out.println("没有任何奖励 "); }
下列语句的执行结果?
int mingCi = 1; switch (mingCi){ case 1: System.out.println("参加麻省理工大学组织的1个月夏令营"); case 2: System.out.println("奖励惠普笔记本电脑一部"); case 3: System.out.println("奖励移动硬盘一个"); default: System.out.println("没有任何奖励 "); } //如果需要每个case执行完后跳出,在每个case后不要忘记写break;
8.2.6 比较switch和多重if选择结构
相同点 都是用来处理多分支条件的结构 不同点 switch选择结构:只能处理等值条件判断的情况,而且条件必须是整型变量或字符型变量 多重if选择结构:没有switch选择结构的限制,特别适合某个变量处于某个连续区间时的情况 if 在应用中更为常见,有时switch 结构更清晰.
8.3 循环结构
8.3.1 循环分类
顺序结构或分支结构的程序语句只能 被执行一次。如果你要同样的操作执行多次,就需要使用循环结构。
执行一些需要重复的操作时,要用到循环流程. 在现实与程序中会大量的用到循环流程 . jdk1.5以后567都叫jdk567. jdk1.5提供了foreach循环(增强for循环),用来遍历集合、数组元素
while循环 do-while循环 for循环 单层for循环 双层for循环 增强for循环(foreach) 嵌套循环 循环语句的四个组成部分: 初始化部分(inni_statement):循环的初始值 循环条件部分(test_exp):是否继续循环 循环体部分(body_statement) 迭代部分(alter_statement)
8.3.2 while循环
语法: while(条件表达式){ 语句块; } 解释: 条件表达式返回值类型为boolean类型,只要条件表达式的结果为true,则一直执行语句块。 特点:先判断,再执行
问题:如何用程序描述下面这个故事呢? 为了帮助张浩尽快提高成绩,老师给他安排了每天的学习任务, 其中上午阅读教材,学习理论部分,下午上机编程,掌握代码部分。 老师每天检查学习成果。如果不合格,则继续进行 分析:使用while循环的步骤 1、分析循环条件和循环操作 2、套用while语法写出代码 3、检查循环是否能够退出
System.out.print("合格了吗?(y/n):"); String answer = input.next(); while(answer.equals("y")==false){ System.out.println("上午阅读教材!"); System.out.println("下午上机编程!\n"); System.out.print("合格了吗?(y/n):"); answer = input.next(); } System.out.println("完成学习任务!");
package Test3; public class WhileDemo { public static void main(String[] args) { int sum = 0; int i = 1; while(i<=10){ sum+=i; i++; } System.out.println("sum:"+sum); } }
8.3.3 do…while循环
语法: 1、初始化部分; do{ 3、循环体部分; 4、迭代部分 }while(2、循环条件); 执行顺序:134——234234——2 解释: 先执行do对应的语句块,然后再判断循环条件,只要循环条件满足,则一直执行循环体,否则结束循环(直到条件不满足为止)。 特点:先执行,再判断。do-while循环至少执行一次循环体。
为什么需要do-while循环?
经过几天的学习,老师给张浩一道测试题, 让他先上机编写程序完成, 然后老师检查是否合格。如果不合格,则继续编写。……
do{ System.out.println("上机编写程序!"); System.out.print("合格了吗?(y/n)"); answer = input.next(); System.out.println(""); }while(!"y".equals(answer)); System.out.println("恭喜你通过了测试!");
8.3.4 while和do while的区别?
执行次序不同: while先判断,再执行;do while先执行,再判断 初始情况不满足循环条件时: while循环一次都不会执行 do-while循环不管任何情况都至少执行一次
package Test3; public class DoWhileDemo { public static void main(String[] args) { int sum = 0; int i = 1; do{ sum+=i; i++; }while(i<=10); System.out.println("sum:"+sum); } }
8.3.5 for循环
语法: for( 初始化循环变量 ; 条件表达式 ; 迭代语句 ){ 循环操作; } 解释: 1.先执行初始化表达式值 2.使用初始表达式值进行条件判断,如果判断为true,则执行循环操作;否则结束循环 3.进行迭代 4.循环迭代可以在()里面省略,在循环体里面进行迭代也可。
循环输入某同学结业考试的5门课成绩,并计算平均分
使用for循环结构的步骤 1、分析循环条件和循环操作 2、套用for语法写出代码 3、检查循环是否能够退出
//省略声明变量 for(int i = 0; i < 5; i++){ //循环5次录入5门课成绩 System.out.print("请输入5门功课中第" + (i+1) + "门课的成绩: "); score = input.nextInt(); //录入成绩 sum = sum + score; //计算成绩和 } avg = sum / 5; //计算平均分 System.out.println(name + "的平均分是:" + avg);
package Test3; /* * for循环语句的格式: * for(初始化语句;判断条件语句;控制条件语句){ * 循环体语句; * } * * 执行流程: * 1.执行初始化语句; * 2.执行判断条件语句; * 3.执行循环体语句; * 4.执行控制条件语句; * 5.回到2在开始执行,直至不符合控制条件语句. * */ public class ForDemo { public static void main(String[] args) { int sum = 0; for(int i=1; i<=10;i++){ sum+=i; } System.out.println("sum:"+sum); } }
8.3.6 循环对比
执行顺序 先判断,后执行: while 和 for 先执行,后判定: do-while 适用 循环次数确定: 一般使用for 循环次数不确定: 一般使用while 和 do-while
8.3.7 循环嵌套
循环里面还有循环,可以嵌套多层,不同的循环结构相互之间也可以嵌套。
首先内层循环属于外层循环循环体的一部分,当循环体执行完以后外层循环才进入第二次循环,此过程中内层循环需要执行符合条件的完整循环。
第一个(外层)for循环作用:控制行数
第二个(内层)for循环作用:控制列数
循环嵌套练习1:
/* 第一行 * 第二行 ** 第三行 *** 第四行 **** 第五行 ****** */ public class Test { public static void main(String[] args) { /* * 外层控制行数 * 内层控制星号的个数 */ for (int i = 1; i <=5; i++) { for(int j=1;j<=i;j++){ System.out.print("*"); } System.out.println(); } } }
循环练习2:
/* 1 * 4个空格 2 *** 3个空格 3 ***** 2个空格 4 ******* 1个空格 5 ********* */ public static void testFor() { for(int i=1;i<=5;i++){ for(int j=1;j<=n-i;j++){ System.out.print(" "); } for(int j=1;j<=2*i-1;j++){ System.out.print("*"); } System.out.println(); } } public static void testFor1() { for (int i =1; i <=5; i++) { for(int j=5; j>=i; j--){ System.out.print(" "); } for(int j=1;j<=i*2-1;j++){ System.out.print("*"); } System.out.println(); } }
8.4 流程的跳转
break 用于do-while、while、for、switch中时,可跳出循环而执行循环后面的语句 continue 用在循环中,跳过本次循环,执行下一次循环.
8.4.1 break
while(…) { …… break; …… } //break通常在循环中与条件语句一起使用
问题:循环录入某学生5门课的成绩并计算平均分,如果某分数录入为负,停止录入并提示录入错误 分析:循环录入成绩,判断录入正确性:录入错误,使用break语句立刻跳出循环;否则,累加求和
…… for(int i = 0; i < 5; i++){ //循环5次录入5门课成绩 System.out.print("请输入第" + (i+1) + "门课的成绩: "); score = input.nextInt(); if(score < 0){ //输入负数 break; } sum = sum + score; //累加求和 } …循环外的语句…
8.4.2 continue
语法: while(...){ ....语句块1; continue; ....语句块2; }
循环录入Java课的学生成绩,统计分数大于等于80分的学生比例 1、通过循环,获得分数大于等于80分的学生人数num 2、判断:如果成绩<80,不执行num++,直接进入下一次循环
for (int i = 0; i < total; i++) { System.out.print("请输入第" + (i + 1) + "位学生的成绩: "); score = input.nextInt(); if (score < 80) { continue; } num++; } System.out.println("80分以上的学生人数是: " + num); double rate = (double) num / total * 100; System.out.println("80分以上的学生所占的比例为:" + rate + "%");
8.4.3 对比break和continue
使用场合不同 break可用于switch结构和循环结构中 continue只能用于循环结构中 作用不同(循环结构中) break语句终止某个循环,程序跳转到循环块外的下一条语句。 continue跳出本次循环,进入下一次循环
8.4.4 多层循环跳转
嵌套循环时 : 内循环可以使用外循环中的变量.
外循环每循环一次,内循环都会重新循环,并循环完内循环的所有次.
break/continue 只会控制当前的循环
可以使用给循环设定标签的形式来控制循环.
f1:for( ... ; ... ; ... ){ f2:for( ... ; ... ; ...){ if( ... ){ break f1; } } ... }
九、数组
9.1 什么是数组?
导入: 数组到面向对象:内存解析变量,数组,对象,常量,方法,类这些数据 例如有10000个变量名,10000个值,调用也很麻烦。i1-i10000 变量名全部存储在内存里面,变量值也有10000个,内存造成了严重的浪费。 定义变量就是想把这个值放到内存里面。 程序里面所有运行的数据都是在内存里面放置的。定义变量实质就是存数据到内存里面。 数据存到外存程序就运行不出来了,叫做持久化存储了。存到内存里面叫做临时使用。 调用数据也叫取数据,打印语句。 为什么要定义数组: 比如我们定义一批数据的时候,无论是存,还是取都非常麻烦;(10000) i1 -i10000 存:向内存存储,有10000个变量名和10000个变量值;1、非常浪费内存。 i1 -i10000 取:从内存中取值,比如打印输出,10000次输出语句;2、代码复用率低。 int i1 = 1; int i1 = 1; int i1 = 1; int i1 = 1; int i1 = 1; for(int i1 = 1;i <= 5;i++){ //我们要输出i1-i5变量对应的值 System.out.printIn("i"+i);//i1-i5,输出的是i1-i5的字符串 System.out.printIn("i");//上面这个相当于这一句,也是输出字符串 System.out.printIn(i1);//这才是输出(调用)变量值 } 如果要存储有关联的一批次数据 例如:美团外卖 商品1:图片1,辣椒炒肉,18.5,1200 商品2:图片2,西红柿鸡蛋,8,5,1500 图片一般用地址来操作,也可以数据库。变量之间的关联是松散的,不利于集中管理,不符合命名规范。虽说符合驼峰原则,但是这样命名是不规范的。 String goodsImg1 = "images/XX.png"; String goodName1 = "辣椒炒肉"; double goodsPrice1 = 18.5; int goodsSale1 = 1200; String goodsImg1 = "images/YY.png"; String goodName1 = "西红柿鸡蛋"; double goodsPrice1 = 8.5; int goodsSale1 = 1500; String goodsImg1 = "images/zz.png"; String goodName1 = "辣椒炒肉"; double goodsPrice1 = 18.5; int goodsSale1 = 1200; 如果是用数组来定义呢? 数组会在内存里面定义一连串的存储区域,通过下标标识每个存储区域。这块连续区域可以存储很多值,原来可以把这个数组区域分为无数个各种各样的值。现在对数组内部进行分类。通过一连串下标来标识存储位置。现在就可以通过下标来使用for循环搞定。以后学到面向对象会更简单,一个数组就搞定了。现在没学到就多定义几个数组。一个放图片,一个放价格等,要找的时候就把1的下标拿出来就行,从4个数组里面拿取1的数据。
数组是一个由若干同类型变量组成的集合,每一个变量称为数组的元素或单元。数组通过数组名加索引(下标)来使用数组的元素。 多个相同类型的数据:结论是Java数组只能存储同一类型的数据 和定义变量的类型类似,比如int a,表示a只能存储一个int类型的值。一次性只能存一个,后面再赋值就会被覆盖 了,但也依旧是存取了一个值。声明什么只能存什么类型的。 我们定义数组,也是需要指明存储类型的数据类型: 比如int[] arr,表示数组arr只能存储0个或多个类型的值。 比如String[] names,表示names数组只能存取0个或多个String类型的值。 按一定顺序排列的集合:数组存取数据,是有序,是按照下标来进行的数据存储,下标从0开始。 并使用一个名字命名:数组和变量的区别,数组可以存储多个值,变量只可以存储一个值。 并通过编号的方式对这些数据进行统一管理:数组来管理存储的数据,是通过下标来管理。
数组的特点
数组的长度是固定的。 数组的元素的类型,必须一样 数组的元素,可以是基本类型,也可以是引用类型 数组本身是引用类型
总结: 1、通过一个数组名,可以存储n个值,节省内存空间 2、在我们遍历数据的时候,可以通过循环结合下标来快速实现遍历,提高代码复用性 3、数组存储数据,让我们数据便于集中管理,加强数据的关联性。
9.2 为什么需要数组?
Java考试结束后,老师给张浩分配了一项任务,让他计算全班(30人)的平均分
int stu1 = 95; int stu2 = 89; int stu3 = 79; int stu4 = 64; int stu5 = 76; int stu6 = 88; …… avg = (stu1+stu2+stu3+stu4+stu5…+stu30)/30 思考:30个变量太繁琐
9.3 一维数组的定义
数组是一个变量,存储相同数据类型的一组数据。
声明一个变量就是在内存空间划出一块合适的空间 声明一个数组就是在内存空间划出一串连续的空间 变量的初始化相当于赋值(先声明,后赋值;声明并赋值)
声明数组的语法: 数据(元素)类型 数组名[] = new 元素类型[数组元素个数或数组长度]; 不推荐打空格。 我们可以通过数组名来操作数据里面的数据(数组元素)。 int[] nums = new int[5]; int nums[] = new int[5]; 数组的结构和基本要素 标识符:数组的名称,用于区分不同的数组;数组只有一个名称,即标识符 数组元素:向数组中存放的数据/元素 元素类型:数组元素的数据类型 数组长度固定不变,避免数组越界
数组的要素:
使用数组四步骤: 1、声明数组(数组名实际上就是变量名):告诉计算机数据类型是什么 声明数组包括数组变量的名字(简称数组名)、数组的类型。 用以区分不同的数组。 数组只有有一个名称,即标识符,要符合标识符规范。 声明一维数组有下列两种格式: 数组的元素类型 数组名[]; 数组的元素类型[] 数组名; int[ ] a; int[] saleArr; String[] imgArr; String[] nameArr; double[] priceArr; 2、分配空间:告诉计算机分配几个连续的空间 new表示在堆空间中开辟一块区域,以后碰到new就是在堆空间开辟一块区域。 new有些情况下可以不写,解析的时候会自动补充上来。 new int[5] 在内存中开辟5个连续的区域,用来存储int类型。 动态初始化:创建数组的时候没有赋予值,创建数组之后再赋予值 内存解析:创建长度为5的数组,用来存储int类型的值 1、先开辟了5个连续的区域。2、指向(赋值)给a a = new int[5]; //声明数组并分配空间 int a[] = new int[5]; 数组下标、数组元素是用来存取数据的。 调用a数组,a存储数组的首地址。 int a[] = new int[5]; System.out.println(a);//只会输出一个地址 [I@1b6d3586 一维数组 System.out.println(a[1]);//获取数组第二个值,下标1 结果输出0 原来说过局部变量必须先赋值,不然直接调用,编译就出错了。 编译通过了,那么表示数组有默认初始值。 a = 10;//编译失败,因为a[]是int[]类型,10是int类型,类型不匹配 a里面的每一个空间都是用来存储int类型的。 a[0] = 10; a[1] = 20; a[2] = 30; a[3] = 40; a[4] = 50; System.out.println(a[5]);//编译通过(语法没错),运行错误 编译错误:编译时异常,只是把java源文件生成(翻译)成字节码文件,代码还没执行,只要语法没错,肯定可以编过。 运行错误:运行时异常,运行字节码文件,代码开始运行,那么代码在执行过程中出现问题,就运行失败。 静态初始化: 元素类型[] 数组名 = new 元素类型[]{元素1,元素2,元素3.....}; double[] priceArr = new double[]{12,34.5,55,66,55555}; System.out.println(priceArr[2]);//55.0 //int[5] price = new int[5];//只需要在创建数组开辟空间的时候指明长度,前面的5是声明,后面才是开空间 int[] price = new int[3];//声明数组必须指明长度或者赋值 double[] priceArr1 = new double[]{12,34.5,55,66,55555};//如果是静态赋值,长度由值得个数来决定,priceArr1不要加数字了 3、赋值:向分配的格子里放数据 a [0] = 8; 4、处理数据:对数组的数据进行操作 a [0] = a[0] * 10; 5、元素下标:对数组元素进行编号,元素下标标明了元素在数组中的位置,从0开始,数组中的每个元素都可以通过下标进行访问。"土豆泥"存储在nameArr的下标0的位置,"西红柿"存储在nameArr的下标2的位置,"老干妈"存储在nameArr的下标3的位置。 数组是有序排列的集合。 数组本身是引用数据类型,而数组中的元素可以是任何数据类型,包括基本数据类型和引用数据类型。 数组的元素类型,必须一样。 创建数组对象会在内存中开辟一整块连续的空间 ,而数组名中引用的是这块连续的空间的首地址。 首地址:变量所占的存储区域的第一个单元地址。 数组的长度是固定不变的,避免数组越界。长度一旦确定,就不能修改。 内存有数组不一定有,看数组是怎么规定的。 我们可以直接通过下标(或索引)的方式调用指定位置的元素,速度很快。 对数组元素进行编号,元素下标标明了元素在数组中的位置,从0开始。 数组中的每个元素都可以通过下标来访问。 数组的分类:按照维数,一维数组、二维数组(多维数组以上不常用)、三维数组.... 按数组元素类型分:存储数据类型不一样 基本数据类型元素的数组:double[ ] priceArr; 引用数据类型的元素数组(即对象数组):String[ ] nameArr;
声明数组并赋值
//数组名的元素 int[ ] score = new int[ ]{89, 79, 76}; //不能指明长度 int[ ] score = {89, 79, 76}; String[ ] nameArr = {"土豆泥","西红柿","老干妈".....}; double[ ] priceArr = {18.6,8.5,9.9.....};
案例:
对数据进行处理:计算5位学生的平均分 int [ ] score = {60, 80, 90, 70, 85}; double avg; avg = (score[0] + score[1] + score[2] + score[3] + score[4])/5; int [ ] score = {60, 80, 90, 70, 85}; int sum = 0; double avg; for(int i = 0; i < score.length; i++){ sum += score[i]; } avg = sum / score.length;
总结:一维数组声明方式
以下几种方式,都可以声明数组。 type[] 数组名 = new type[数组中元素的个数] 比如 int arr = new int[10]; type 数组名[] = new type[数组中元素的个数] type[] 数组名 = new type[]{元素1,元素2,..} type[] 数组名 = {元素1,元素2,..}
数组的使用和遍历
遍历数组,可以明确循环次数。 普通for循环遍历数组,数组下标从0开始,到数组.length - 1。<= 普通for循环遍历数组,数组下标从1开始,到数组.length。< 访问数组元素:数组名[元素下标],比如 arr[3]。数组下标是从0开始的 给数组元素赋值:数组名[元素下标] = XXX,比如 arr[3] = 20 获得数组长度:数组名.length,比如 arr.length 遍历数组:通过for循环遍历数组 //增强for循环(Java) //js里面有for in for of循环 for(double s : score) { System.out.println(s); //s就相当于数组里面的每一个值 } //增强for循环遍历数组 public class Kewei { public static void main(String[] args) { int [] score = {60, 80, 90, 70, 85}; //元素类型必须和数组/集合里面存储的数据类型保持一致,因为x就是用来接收数组/集合里面的每一个值。 //int x 相当于声明了一个变量,for循环每执行一次,就把score数组的值赋予给int for(int x:score){//scores里面存储的数据是int类型 System.out.print(x + "\t"); } } } 长度问题: int [ ] score = {60, 80, 90, 70, 85}; for(int i = 0;i < score.length;i++){ System.out.println(score[i] + "\t"); } 越界问题:ArrayIndexOutOfBoundsException:数组下标越界 index索引 outof超出了 bounds范围 默认值问题: 数组一旦确定,那么就会赋予默认的初始值 初始值:byte、short、int、long 0 float、double 0.0 char 0改写为:'\u0000'(表现为空,实际上并不是空) boolean false 引用类型 null关键字 注意:不是这个“null”,这个属于字符串 public class Kewei { public static void main(String[] args) { char[] chars = new char[5]; System.out.println("char类型元素的数组默认值是:" + chars[0] + "hello");//不是' ' //验证前面的不需要下面这些 if (chars[0] == 0){ System.out.println("char类型元素的默认值真的是0吗"); } } }
最简洁的写法:String[] strArr = {"1","2","3"}; 总结:数组一旦初始化完成,其长度就确定了。
常量值和常量: 常量:由final修饰的变量就是常量,在程序运行过程中,不允许修改它的值。 变量值:在程序执行过程中,值不会发生改变。 int a = 10;//变量 a = 100; final int num = 10;//常量 //一旦由final修饰了,那么值不允许发生改变 //num = 100;//编译失败,不可以这样写 System.out.println(10);//只可以这样写
每个数组都有一个属性length指明它的长度,例如: a.length 指明数组a的长度(元素个数) 数组一旦初始化,其长度是不可变(固定了)的。 System.out.println("nums数组的长度是:" + num.length); 静态初始化和动态初始化都可以获取到长度。 面试题: 1、获取数组长度使用length属性还是length方法? 2、获取字符串长度使用length属性还是length方法?
内存解析: import java.util.Scanner; public class Kewei { public static void main(String[] args) { /*面试题: *基本类型的变量数据:我们定义的基本数据类型的变量,存储的值; *局部变量:定义在方法或语句中的变量 *栈里面存储的: * a\b\ch\bl\scanner都是定义在main()方法中的局部变量 * 10,20.23,'H',true都是基本类型的变量数据 * 对象的引用(其实就是首地址),例如创建Scanner类对象。 * 堆里面存储的: * 存放new出来的对象:new Scanner(System.in) * 数组 * 对象的实例对象 * */ int a = 10; double b = 20.32; char ch = 'H'; boolean bl = true; Scanner scanner = new Scanner(System.in); } }
案例一:计算平均分 public class Kewei { public static void main(String[] args) { int[] scoreArr = {60, 80, 90, 70, 85}; int sum = 0; for(int i = 0;i < scoreArr.length;i++){ sum = sum + scoreArr[i];//或写成sum += scoreArr[i]; } System.out.println("\n5名学生的平均分是;" + (sum/scoreArr.length)); } }
9.4 二维数组的定义
二维数组就是数组套数组,相当于一个表格。数组里面套数组。 格式: 元素类型[][] 数组名 = new 元素类型[一维长度][二维长度]; 元素类型[][][] 数组名 = new 元素类型[一维长度][二维长度][三维长度]; 例子:int[][] arr = new int[3][2] 例子解析: 二维数组里面有3个一维数组,每个一维数组里面有2个元素。 把外层叫做二维数组,内层的叫做一维数组。 创建了3个连续的空间,每个空间里面存值。 System.out.pritnln(arr);//获取到二维数组的首地址 [[I@1b6d3586
二维数组本质上是以数组作为数组元素的数组,即“数组的数组”
声明二维数组有下列两种格式
数组的元素类型 数组名[][]; 数组的元素类型 [][] 数组名; 例如: char cat[][]; char[][] cat;
二维数组和一维数组一样,在声明之后必须用new运算符为数组分配内在空间。
例如: int[][] mytwo; mytwo = new int [3][4];
声明数组和创建数组可以一起完成,例如:
int mytwo[][] = new int[3][4];
Java采用“数组的数组”来声明多维数组。上述创建的二维数组mytwo就是由3个长度为4的一维数组:mytwo[0]、mytwo[1]和mytwo[2]构成的。
9.5 使用数组
一维数组通过索引符访问自己的元素,如boy[0],boy[1]等。需要注意的是索引从0开始 。
二维数组也通过索引符访问自己的元素,如
a[0][1],a[1][2]等。需要注意的是索引从0开始。
比如声明创建了一个二维数组a:
int a[][] = new int[2][3];
那么第一个索引的变化范围为从0到1,第二个索引变化范围为从0到2。
length的使用
数组的元素的个数称作数组的长度。
对于一维数组,“数组名.length”的值就是数组中元素的个数。
对于二维数组,“数组名.length”的值是它含有的一维数组的个数。
例如,对于
float a[] = new float[12]; int b[][] = new int[3][6]; a.length的值12;而b.length的值是3。
9.6 数组的初始化
创建数组后,系统会给数组的每个元素一个默认的值,如,float型是0.0。
在声明数组的同时也可以给数组的元素一个初始值,如:
float boy[] = { 21.3f,23.89f,2.0f,23f,778.98f};
也可以直接用若干个一维数组初始化一个二维数组,这些一维数组的长度不尽相同,
例如:
int num = 100; int[][] a= {{1}, {1,1},{1,2,1}, {1,3,3,1},{1,4,6,4,1}};
public class Kewei { public static void main(String[] args) { int[][] arr = new int[3][2]; System.out.println(arr);//[[I@1b6d3586 System.out.println("二维(外层)数组的长度是:" + arr.length);//3 System.out.println(arr[0]);//[I@4554617c System.out.println(arr[1]);//[I@74a14482 System.out.println(arr[2]);//[I@1540e19d System.out.println("一维(内层)数组的长度是:" + arr[0].length);//2 System.out.println("默认初始值是:" + arr[1][1]); arr[1][1] = 10000; System.out.println("修改后的值:" + arr[1][1]); //没有初始化,数组是引用类型,默认值是null int[][] arr1 = new int[3][]; System.out.println(arr1[1]);//null //null调用属性和方法,都会抛出空指针 异常NullPointerException //System.out.println("一维(内层)数组的长度是:"+ arr1[0].length);//运行时异常 arr1[0] = new int[3]; arr1[1] = new int[5]; arr1[3] = new int[2]; //静态初始化 int[][] arr2 = new int[][]{{3, 8, 2}, {2, 7}, {9, 0, 1, 6}}; //错误情况 //String[][] arr3 = new String[][2]; //String[4][3] arr4 = new String[][]; //int[][] arr5 = new int[4][3]{{1,2,3},{4,5},{6,7,8},{1,2,5}}; //正确简洁写法 int[] arr6[] = new int[][]{{1, 2, 3}, {4, 5, 9, 10}, {1, 2}}; int[] arr7[] = {{1, 2, 3}, {4, 5, 9, 10}, {1, 2}}; } }
9.7 数组的引用
数组属于引用型变量,因此两个相同类型的数组如果具有相同的引用,它们就有完全相同的元素。
例如,对于int a[] = {1,2,3}, b[ ]= {4,5};数组变量a和b分别存放着引用0x35ce36和0x757aef。
如果使用了下列赋值语句(a和b的类型必须相同)a=b;那么,a中存放的引用和b的相同,这时系统将释放最初分配给数组a的元素,使得a的元素和b的元素相同。
9.8 数组的遍历
基于循环语句的遍历,语法格式如下:
for(声明循环变量:数组的名字) {
… …
}
其中,声明的循环变量的类型必须和数组的类型相同。
可以将这种形式的for语句中翻译成“对于循环变量依次取数组的每一个元素的值”。
一维数组遍历示例:
public class Demo11{ public static void main(String args[]){ int a[] = {1,2,3,4}; //创建一个int类型的数组 System.out.println("数组元素的个数:"+a.length); System.out.println("a[1]:"+a[1]); //通过下标来访问具体的数组元素 for(int i=0;i<a.length;i++){ //执行完后,会把数组中每个元素都遍历到 System.out.println("a["+i+"]:"+a[i]); } } }
二维数组的遍历:
int arr[][] = {{1,2,3},{11,12,13,14},{22,33,44,55,66,77},{1}}; //普通for循环遍历二维数组 for(int i = 0;i < arr.length;i++) { int ewArr[] = arr[i]; //一维数组里面的每个数组 for(int j = 0;j < ewArr.length;j++) { System.out.print(ewArr[j]+"\t"); } System.out.println(); } System.out.println("--------------------------------"); //增强for循环变量 for(int ewArr[] :arr) { for(int x : ewArr) { System.out.print(x+"\t"); } System.out.println(); }
案例1:杨辉三角 public class Kewei { public static void main(String[] args) { int[][] yangHuiArr = new int[10][]; //创建十行 for (int i = 0;i < yangHuiArr.length;i++){ //分配每一行的空间 yangHuiArr[i] = new int[i + 1]; yangHuiArr[i][0] = yangHuiArr[i][i] = 1; if(i > 2){ for (int j = 1;j < yangHuiArr[i].length - 1;j++){ yangHuiArr[i][j] = yangHuiArr[i - 1][j - 1] + yangHuiArr[i - 1][j]; } } } for(int arr[]:yangHuiArr) { for(int num : arr){ System.out.print(num +" "); } System.out.println(); } } } 案例2:创建一个长度为6的数组,要求取值为1-30(随机数),同时元素值各不相同 public class Kewei { public static void main(String[] args) { int[] nums = new int[6]; // Math.random() 获取0-1的伪随机数包含0但不包含1,,默认结果类型是double类型 //不包含1的意思就是永远得不到30 //向上取整也可以 //Math.random() * 30; //Math.random() * 30 + 1 得到1到31,不包含31,截断(强转) //i指的是第几个数,表示个数的意思 for (int i = 0; i < nums.length; i++) { int randomNum = (int) (Math.random() * 30 + 1); nums[i] = randomNum; if (i >= 1) { for (int j = 0; j < i; j++) { if (nums[j] == randomNum) { i--; break; } } } } for (int i : nums) { System.out.println(i + "\t"); } } } 案例3:定义一个int类型的一维数组,包含10个元素,分别赋一些随机整数,然后求出所有元素的最大值,最小值,和值,平均值,并输出出来。要求所有随机数都是两位数。
十、continue、break、return三者区别
continue: 跳过本次循环,继续下一次循环 break: 结束所在的循环。 return: 结束整个方法
扩展:
System.exit(int num):结束整个进程()
十二、冒泡排序
12.1 简介
冒泡排序(Bubble sort),是一种简单的排序算法。
它重复地循环要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。
12.2 算法步骤
-
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
-
对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
-
针对所有的元素重复以上的步骤,除了最后一个。
-
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
12.3 复杂度
若文件的初始状态是正序的,一趟扫描即可完成排序。所需的关键字比较次数 和记录移动次数 均达到最小值: 所以,冒泡排序最好的时间复杂度为O(n)。
若初始文件是反序的,需要进行n-1趟排序。每趟排序要进行n-i次关键字的比较(1≤i≤n-1),且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较和移动次数均达到最大值: 冒泡排序的最坏时间复杂度为O(n2)。
综上,因此冒泡排序总的平均时间复杂度为O(n2)。
空间复杂度为O(1);
12.4 稳定性
冒泡排序是稳定排序,不会改变数据的大小相对位置;
12.5 具体实现
最简单粗暴的实现方式,每次循环次数ary.length-1;
for (int i = 0; i < a.length - 1; i++) { for (int j = 0; j < a.length - 1; j++) { if (a[j] > a[j + 1]) { int tmp = a[j]; a[j] = a[j + 1]; a[j + 1] = tmp; } } }
由上可以看出,对于已经排序好的最大元素,可以直接忽略。
精简,后续每次循环 次数 -i;
for (int i = 0; i < a.length - 1; i++) { for (int j = 0; j < a.length - 1 - i; j++) { if (a[j] > a[j + 1]) { int tmp = a[j]; a[j] = a[j + 1]; a[j + 1] = tmp; } } }
对于原本顺序就是正常,或者某步的时候已经排好,则不需要进行所有排序,这里添加标志位,对于一次循环,不需要进行换位置,说明已经排序完成。直接退出。
for (int i = 0; i < a.length - 1; i++) { boolean flag = false; for (int j = 0; j < a.length - 1 - i; j++) { if (a[j] > a[j + 1]) { int tmp = a[j]; a[j] = a[j + 1]; a[j + 1] = tmp; flag = true; } } if(!flag) { System.out.println("排序已完成"); break; } }
https://blog.csdn.net/lu_1079776757/article/details/80459370
https://www.jianshu.com/p/1458abf81adf
标签:01,变量,int,System,运算符,String,数组,println,out From: https://www.cnblogs.com/lkw-lkw/p/kewei_com.html