史上最全的Java学习路线
java基础
一、Java的历史和三大版本
1. Java的发展史
Java由sun公司开发,java之父 James Gosling Java是一门面向对象的编程语言,也称为“高级编程语言”
Java在1994年由sun公司推出,Java的前身叫oak语言,开源,免费
Java的版本从JDK1.0开始 到目前的JDK13
目前开发常用版本: JDK8.0、JDK9.0
2. Java语言能做什么
Java语言主要用于互联网应用程序开发,例如 天猫、京东、 大型公司的项目管理系统、手机APP的后台数据支撑系统 ,主要开发web系统(基于浏览器访问的) ,还有服务器后台存储的数据分析,数据查询等相关系统。
-
Java的版本分类
a、Java SE (J2SE) Java PlatForm Standard Edition Java的标准版本(称为Java基础)
b、JavaEE (J2EE) Java PlatForm Enterprise Edition Java的企业版本
c、JavaME (J2ME) Java PlatForm Microsoft Edition Java的微型版本
二、Java的开发环境
1. 配置开发环境
第一步 下载jdk 并安装 ,建议安装在默认c盘 官网下载
第二步 配置环境变量
我的电脑-》 属性-》 高级系统设置-》 环境变量 --》 新建 一个系统变量 ,变量名
JAVA_HOME : C:\Program Files\Java\jdk1.8.0_144
在path路径下 ,配置 %JAVA_HOME%\bin , 需要将该路径放置path的最前面
或者直接在path下配置 “C:\Program Files\Java\jdk1.8.0_144\bin”
第三步:测试
win+r : 运行窗口 中输入cmd
输入 Java
输入 javac
环境变量配置成功
三、Java的第一个程序及运行原理
Java程序是一个 以.java结尾的文件 , 称为“源程序”
Java程序需要运行 ,必须经过两个步骤: 先编译 再运行,将源程序先编译成.class文件 ,编译后的class文件称为“字节码”文件 ,然后再由Java虚拟机(JVM)运行 文件,最后得到结果 。
JDK : Java Development Kit Java开发工具 ,包括Java开发中 运用的所有工具(包,接口API等,运行环境等)
JRE :Java Runtime Environment Java运行环境 , 运行Java程序需要的相关依赖
JVM : Java Virtual Mechine Java虚拟机器, 用于运行Java程序实现跨平台虚拟计算机。
JVM 的组成部分
1、寄存器(程序计数器)
2、本地方法区
3、堆区(堆内存)
4 、栈区(栈内存)
5、 方法区
写第一个Java程序
1、新建HelloWorld.java 文件
2、编写Java程序 ( 文件名与类名 保持一致)
public class HelloWorld{
// 这里是程序的入口 main函数
public static void main(String [] args){
System.out.println("hello word!!!!");
}
}
3、编译java程序 (Compile)
在文件所在的目录下输入cmd ,打开命令行窗口 输入
javac HelloWorld.java
4、运行java程序
java HelloWorld (注意这里没有后缀.java )
注意 :对于中文输出乱码,需要 另存为一下,修改编码格式为ANSI 即可
Java文件 一次编译多次运行
Java的运行原理图:
四、Java的开发工具
Java开发使用集成开发环境,一般企业使用居多的 eclipse 或 IDEA 开发工具
idea常用快捷键
alt+enter : 自动导入包, 代码自动修正
ctrl+d :将当前光标 所在行 复制到下一行
ctrl+ y : 删除光标所在的 当前行
ctrl+alt+l : 格式化代码
ctrl+ / : 当行注释
ctrl+shift+/ : 文档注释
创建项目:
方式一: 直接创建项目 在src下创建包和类文件 ,每次创建项目都是独立窗口
方式二: 先创建一个空项目(Empty Project) ,再创建子模块Module ,好处是一个项目下可以存放多个子模块
给文件增加文件头注释
/**
* @Author: wuyafeng by softeem
* @Date: ${DATE} ${TIME}
* @Description:
*
*/
Java的注释 分为三种
1、单行注释(ctrl+/) : 用于对某一句代码的注释
2、多行注释(ctrl+shift+/): 用于对一段代码的注释
3、文档注释 (/** + enter) : 注释一个类 或 一个方法, 或一个语句块 ,文档注释可以自动生成API文档 javadoc 命令
五、Java的关键字和标识符
关键字
1、定义:
在Java程序中,已经定义好的被预先使用的一些特殊的单词称为关键字 ,一共有50个关键字 (48+2个保留字) ,关键字都是小写的英文单词
2、关键字的分类
2.1 数据类型关键字
byte :字节类型
short : 短整型
int : 整型
long: 长整型
float :单精度浮点型
double:双精度浮点型
char: 字符型
boolean : 布尔类型
void :空类型
null :空对象
2.2 流程控制关键字
if: 条件分支判断
else:条件分支
switch: 条件分支判断
case : 条件分支其中一种情况
default : 默认
break: 退出条件 或 循环
continue : 退出当前循环,继续下一次循环
for : 循环
do: 循环
while : 循环
return:方法的返回
2.3 面向对象关键字
class:定义类
interface : 定义接口
extends:继承一个类
implements: 实现一个接口
super : 超级 (用于调用父类的成员)
this: 当前类
instanceof : 判断一个类的类型
import : 导入一个类
package : 定义一个类所在的包
new : 创建对象
2.4 修饰符关键字
abstract :修饰抽象类 、抽象方法
final : 修饰常量
native: 本地的 ,也用于修饰变量
private :私有的
protected : 受保护的
public : 公共的
static :静态的
synchronized :修饰方法或代码块,用于线程安全的
transient :瞬时状态
volatile :瞬时状态
2.5 异常关键字
try:试一试
catch: 捕获异常
finally: 最后执行的代码块 ( 多出的一个)
throws :定义需要抛出的异常
throw:抛出异常
2.6 其他关键字
assert :测试中的断言
strictfp : 其他
enum:定义枚举
2.7 保留字
const 、goto
标识符
1、定义
在Java程序中,所有由程序员自己命名的元素统称为“标识符”
2、标识符命名规则
标识符由数字、字母、下划线和$组成
标识符不能以数字开头
标识符区分大小写
标识符不能是关键字
注意事项:
定义类名的标识符 :首字母必须大写 ,后面的单词的首字母大写,准寻 大驼峰命名法 (例如 XxxXxx ,UserInfo ,Student)
定义方法标识符: 首字母尽量小写 ,后面的单词首字母大写,准寻 小驼峰命名法(例如 xxxXxxx , getUserName() )
定义变量标识符: 单词全部小写 ( username)
定义包名: 按模板分层级, 使用公司的域名 倒写,(例如 com.softeem.xxx 、com.j2008.xxx)
定义项目名: 尽量使用英文 (Java项目 可以使用中文,JavaWeb项目一定使用英文)
标识符 | 是否符合 | 标识符 | 是否符合 |
---|---|---|---|
_$abc | ok | $username | ok |
Abc | ok | USERNAME | ok |
this | no | #stu | no |
1username | no | NULL | ok |
null | no | n1 | ok |
六、Java的常量和变量
常量
1、定义
在Java中,固定不变的数据量称为常量,常量也有内存,常量存放在被称为“常量池”的内存中
面试题: 常量池的内存有哪些? (存放常量的内存有哪些 )
2、常量的分类
常量类型 | 含义 | 示例 |
---|---|---|
整数常量 | 所有的整数 | 1,100,500 ,-20 |
小数常量 | 所有的小数 | 1.5,-3,4 ,3.1415926… |
字符常量 | 由单引号引起来,只能写一个字符,不能为’’ | ‘a’ ,‘2’ ,’ ’ |
字符串常量 | 由双引号引起来,可以写多个字符,可以为“” | “hello” “\n” “\t” |
布尔常量 | 用于条件判断的 , 只有2个常量 | true 、false |
空常量 | 用于表示空对象 | null |
常量的修饰符 : final
final int n = 100 ; // 定义常量的语法 ,n的值只能为 100,不能再次改变 ,其中n就是常量
变量
1、定义
在Java中用于保存一个数据的最小内存单元 称为 “变量” ,变量中每次只能存放一个值 ,变量的数值是可以被改变的 。
在定义变量时,需要明确三要素: 数据类型 、 变量名(标识符)、变量值
2、变量语法:
数据类型 变量名 = 初始值;
或者 数据类型 变量名1 ,变量名2 ;
// 定义一个变量 变量名是n ,数据类型是int ,初始值为100
int n = 100 ;
// 将原有变量名n中的值变更为 110
n=110;
变量在赋值时,值必须满足与数据类型匹配,如果不匹配可能出现异常 或丢失精度
3、变量的分类 :
全局变量(global variables)
在Java的类结构中,定义在类中,方法外面的变量, 它的作用范围: 整个类的方法中
public class Test1 {
//定义全局变量 :定义在类里面,方法的外面
int n = 100;
//定义方法
public void m(){
// 输出一句话 "" 表示输出的内容 + 表示连接两个字符串
System.out.println("n:"+n);
}
//定义方法
public void s(){
System.out.println("n:>>>"+n);
}
}
局部变量(local varibable)
一般声明在方法或代码块(条件语句块,循环语句块,静态语句块等) 中,它的作用范围只能在声明的区域中使用
// 定义run方法
public void run(){
// 局部变量 只能在声明所在的方法中使用
int n=200;
int i =1;
// 当类总存在局部变量和 全局变量同名时, 变量的使用遵循“就近原则”
System.out.println("局部变量n:"+ n); // 200
}
// 定义eat方法
public void eat(){
// System.out.println("i---"+i);
}
调用方法的语法
public static void main(String [] args){
// 如何调用 这个类的方法呢? 需要创建对象
// 创建对象的语法: 类名 对象名 = new 类名();
//调用对象的方法语法: 对象名.方法名();
Test1 obj = new Test1();
obj.m();
obj.s();
obj.run();
obj.eat();
}
七、Java的数据类型
Java是一门强类型的编程语言,它不同于一些弱类型的语言(JavaScript ,php,python),Java在声明变量时必须显示的定义变量的数据类型,变量的类型一旦定义,则不能改变 。Java中数据类型分为两大类
1、基本数据类型 : 包括 整数,浮点,字符,布尔类型等
2、引用数据类型 :包括 类,数组,集合,接口等
1、基本数据类型
- 整数型 ,默认值为0
数据类型 | 关键字 | 字节长度 | 数值范围 |
---|---|---|---|
字节型 | byte | 1个字节=8位 | -128~127 |
短整型 | short | 2个字节=16位 | -32768~32767 |
整型 | int(默认) | 4个字节=32位 | -2的31次方 ~2的31次方-1 |
长整型 | long | 8个字节=63位 | -2的63次方~2的63次方-1 |
-
浮点型,默认值为0.0
数据类型 关键字 字节长度 范围 单精度 float 4个字节 1.4013E-45~3.4028E+38 双精度 double 8个字节 4.9E-324~1.7977E+308 -
字符型 默认值 ‘ ’
数据类型 关键字 字节长度 范围 字符型 char 2个字节 0~65535 一个字符能存放一个中文汉字
-
布尔型 默认值 false
数据类型 关键字 字节长度 范围 布尔类型 boolean 1个字节 true、false 注意:
// 对于两个double类型/float类型的数计算, 由于计算机在计算式会缺失精度,计算的结果 //不是预期的0.3,建议对于浮点数计算式,使用java.math.BigDecimal引用数据类型计算 double d1 =0.1; double d2 = 0.2; //结果 0.30000000000000004 double d3 = d1 + d2; System.out.println(d3); float f1 =0.2f; float f2 = 0.3f; float f3 = f1-f2; // 结果 -0.1000000000001 System.out.println(f3);
对于字符类型中 "\ " 表示转移字符,不会占用内存
\n :换行
\t : 一个制表符tab
\b: 表示退格
\r: 表示enter
2、引用数据类型
在Java中除了8个基本数据类型以外的数据类型,都是引用数据类型 ,常用的引用数据类型 包括 类、数组、 接口,String 等
以类 举例
创建一个学生类 ,在一个类中会包含一些 变量(全局变量),还包含一些方法
定义一个学生类,这个类就是引用数据类型
public class Student{
// 定义的一个字符串变量
String stuname="张三";
char sex= '男';
int age = 20;
// 定义一个方法
public void showInfo(){
System.out.println(stuname);
System.out.println(sex);
System.out.println(age);
}
}
如何使用这个学生类型(引用数据类型)
public static void main(String [] args){
// 定义学生类型 ,引用数据类型需要创建 引用的对象
// 引用数据类型 变量名 = null
// 基本数据类型 变量名 = 初始值
// 对于类的创建
// 类名 对象名 = new 类名();
Student stu = new Student();
// 对象名.方法名();
stu.showInfo();
}
引用数据类型与基本数据类型的区别?
1、创建方式不同 ,基本数据类直接通过定义变量的方式创建, 而引用数据类型需要new一个对象
2、在JVM的内存分配不同, 基本数据类型的内存在栈内存中直接创建 , 而引用数据类型是在栈内存中定义引用的地址,实际的内存分布在堆内存中
3、引用数据类型 可以调用它的方法, 而基本数据类型没有方法
基本数据类型的分布:
八、Java的数据类型的转换
为什么需要进行数据类型转换
在Java中数据进行计算时 ,必须要求计算的元素的数据类型一致,如果数据类型不一致需要进行转换
数据转换分类
1、自动类型转换
转换规则: 范围小的类型向范围大的类型转换(从小到大转换)
byte -> short -> int-> long -> float -> double 其中boolean类型不参与转换
char ->int
转换原理: 类型向上提升
2、强制类型转换
- 整数之间的强转
// int 类型
int i=1;
// byte 类型
byte j=100;
// 由于i和j 不同类型,不能直接计算,程序会自动将j的类型向上提升为 int
// 所以i +j 之后依然是 int 类型
// 此时 int 的内存 大于 byte 的内存,会出现数据溢出的情况 ,JVM不允许
// byte s = i + j ; // 等号两遍类型不匹配
int y = i + j ;
System.out.println(y);
// 如果一定要使用byte赋值,还有一种办法,就是将两遍类型一致
byte s = (byte)(i + j) ; // 两个数在相加时 会先自动提升为int 然后再相加
- 整数与小数之间的强转
// 整数和小数之前 也会丢失精度
int n2 = 100;
double n3 = 3.5;
int n4 = (int)(n2 + n3);
// 相加时先提升为 double ,然后相加后得到 double
// double是8个字节 不能放在4个字节的长度中,
// (这里好比double 为一桶水, int为一杯水,相当于将一桶水往一杯水中放)
// 只能留住一本水的内容,所以 这里 如果强转成int 则小数会丢失,
System.out.println(n4);
- 小数和小数之间的强转
// float 与 double 类型
float f1 = 3.14f;
double d2 = 3.5;
double dd = f1+d2;
float ff = (float)(f1 + d2);
- 丢失精度的情况
// 强转时会丢失精度
byte n=100;
int m = 30;
byte mm = (byte)( n + m); // 因为最大值为127 再往后就是从最小值开始-128
System.out.println(mm);
// 整数和小数之间 也会丢失精度
int n2 = 100;
double n3 = 3.5;
int n4 = (int)(n2 + n3);
九、Java的字符ASCII码表
字符 | int值 |
---|---|
a | 97 |
A | 65 |
0 | 48 |
依次小写字母往后都是数字 ,例如 b为98,c为99… | |
A:65 B:66 C:67 0:48 1:49 2:50… |
字符与数值的转换
// int 与 char类型的转换
// 每一个char类型都有一个字符编码 这个编码参照 ASICC码表
char c='a';
// 自动提升 : 因为 char类型占2个字节, int占4个字节,自动char向上提升
int n = c;
System.out.println(n);
// 先相加 再转换
char c2 = (char)(n+2); // 需要强转
// 字符+字符 直接相加
char c3 = 'a'+'b';
System.out.println((int)c3);
十、运算符
在Java中用于程序计算的操作符统称为运算符,运算符分为如下几类
1、算术运算符
运算符 | 说明 | |
---|---|---|
+ | 加号两遍是数值,可以运算,如果一边存在字符串,则当做连接符 | a+b |
- | 两个数相减 , 减号也可以表示负数 | a-b -a |
* | 两个数相乘, 其中*不能省略 | a*b |
/ | 两个数相除,必须保证数据类型一致,其中除数不能为0 ,否则出现算术异常 | a*b |
% | 对一个数取余数 | a%b |
++ | 对一个数 自加1 | a++ 、++a |
– | 对一个数自减1 | a–、--a |
// 总结 ++ – 的优先级高于 + ,-,*,、,%
public static void main(String [] args){
// + - * / % 所有运算符在计算式必须保证 数据类型一致
int num1 = 100;
int num2 = 200;
int sum = num1 + num2;
int mul = num1-num2;
int num3 = -num2; // -200
System.out.println("两个数相加" + sum); // + 表示连接符
System.out.println("两个数相减" + mul);
System.out.println( "num2: " + num2+ " ,num3:" + num3 );
System.out.println("num1+num2="+ (num1+num2) );
int sum2 = num1*num2;
int sum3 = num1/num3;
System.out.println(sum3); // 控制台输出的快捷键 sout+ enter
// System.out.println(num1/sum3); //算术异常:ArithmeticException: / by zero
// 取模
System.out.println( 10%2);//0
System.out.println(1%5);// 1
System.out.println(2%5);
}
public static void main(String[] args) {
// 自加 自减 ++ -- 只能对整数进行
int i=1;
i++ ; // i = i + 1
System.out.println("i:" + i);
int j=1;
++j; // j = j + 1
System.out.println("j:" + j);
int a =1;
int sum = a++; // 先将a的值赋值给sum ,a再自加1
int sum2 = ++a; // 先将a自加1 ,再将自加后的结果赋值给sum2
System.out.println("sum:" + sum);
System.out.println("sum2:" + sum2 );
System.out.println("a:" +a); // 3
int sum3 = a++ + a++ ;
System.out.println("sum3:"+sum3);
System.out.println("a:"+a);
// -- 操作 与++操作类似
int b=1;
int s1= b--; // b = b -1 s1 的值为 先赋值再自减1 s1 = 1
int s2 = --b; // b = b -1 s2 的值为 先自减1 ,再赋值 s2 = -1
System.out.println("b:"+b);
System.out.println("s1:"+s1);
System.out.println("s2:"+s2);
// ++ -- 综合
int x=1;
int y=2;
int s3 = x++ + --x * (y-- + ++x);
System.out.println("x:"+x);// 2
System.out.println("y:"+y);// 1
System.out.println("s3:"+s3);// 5
}
2、比较运算符
用于比较两个表达式之间的 结果 , 结果返回true 、false
比较运算符不能单独作为 一行代码运行 ,必须接收结果或者输出
比较运算符 | 说明 | 案例 |
---|---|---|
> | 比较左边的数是否大于右边的数,如果大于返回true,否则返回false | a>b ,3>5 |
< | 比较左边的数是否小于右边的数,如果大于返回true,否则返回false | a<b |
>= | 比较左边的数是否大于等于右边的数,如果大于返回true, 否则返回false | 1>=2 |
<= | 比较左边的数是否小于等于右边的数,如果大于返回true ,否则返回false | 1<=2 |
== | 比较==两遍是否相等,如果相等则返回true ,否则返回false ,对于基本数据类型比较数值是否相等, 对于引用数据类型比较 它们的地址是否相等 (比较地址就是比较是否同一块内存) | 1==2 |
!= | 与== 相反, 比较左边和右边的数是否不相等 。如果不相等返回true ,如果相等返回false | 1!=2 |
注意: 不能连写 例如 1<3<5
public static void main(String[] args) {
// 比较运算符
int a =1;
int b =2;
// a>b; // 不能单独比较 必须接受结果或输出
System.out.println(a>b); //false
System.out.println(a<b); //true
System.out.println(a==b); //false
System.out.println(a!=b); //true
// 增加逻辑判断
// 如果 if 后面的条件成立, 则执行if里面的语句 ,如果不成立 则只需else语句
if(a>b){
System.out.println("a>b成立");
}else{
System.out.println("不成立");
}
}
3、赋值运算符
将表达式 的结果 赋值给一个变量,只能赋值给变量 不能赋值给常量
例如: a = 3
赋值运算符 | 说明 | 案例 |
---|---|---|
= | 将=右边的结果 赋值给左边的变量 | int a = 2 ,将2赋值给变量a |
+= | 计算后的赋值,将+=右边的结果赋值给左边的变量 | a+=2 等价于 a = a +2 |
-= | 计算后赋值,将-=右边的结果赋值给左边的变量 | a-=b 等价于 a = a-b |
*= | 同上, 将右边的结果赋值给左边的变量 | a*=b 等价于 a = a * b |
/= | 同上,将右边的结果赋值给左边的变量 | a /=b 等价于 a = a/b 其中b!=0 |
%= | 同上,将右边的结果赋值给左边的变量 | a %=b 等于 a= a%b 其中b!=0 |
// 赋值运算符 = += -= *= /= %=
int a=2;
a+=2;
System.out.println(a);// 4
a-=3;
System.out.println(a);// 1
a*=2;
System.out.println(a); // 2
a/=4;
System.out.println(a);// 0
a+=a-=3; // a+=(a-=3) -》 a=a +(a=a-3 )
System.out.println("a="+a);
int x=2;
x+=x-=x*=x++;
//x = x +(x = x -( x= x *(x++) ))
// x = 2 + ( x = 2 - (x = 2 * 2))
// x = 2 + ( 2 - 4)
// x = 0
System.out.println("x="+x);
//赋值运算符的优先级最低, 从右往左计算
int y=2;
y*=y+=y; // 也是从右往左计算
// y = y * (y = y + y);
// y = 2 * (2+2)
// y =8;
System.out.println("y="+y);
4、逻辑运算符
在Java中用于两个或两个以上的表达式 取逻辑判断的结果 ,通常需要使用逻辑运算符
逻辑运算符 | 说明 | 案例 |
---|---|---|
& | 逻辑与 ,左右两边可以连接表达式 ,两个表达式都成立时,整个结果为true | true&true、 false&true false&false 、 true&false |
| | 逻辑或,左右两边的表达式,任意一个成立,整个结果为true | true|true false|true true|false false|false |
! | 逻辑非 对表达式取反 | !false !true |
&& | 短路与 , 与&类似 ,短路 特点: 符号左边为false,右边不再运算 | true&&true true&&false … |
|| | 段落或, 与| 类似,段落忒点: 符号左边为true ,右边不再运算 | false||true false||false |
// 逻辑运算符
System.out.println(true & true); // true
System.out.println(true & false);// false
System.out.println(false & true); // false
System.out.println(false & false);// false
// true&true
System.out.println(1>0 & 3>1);
System.out.println(1>0 && 3>1);
// | 或
System.out.println(true | true); //true
System.out.println(true | false);// true
System.out.println(false | true); // true
System.out.println(false | false);// false
// || 短路或
System.out.println(true || false) ;// true
总结: &与&&的区别 |与||的区别?
回答 1、& 对于符号两边的表达式都会执行 && 符号左边为false,则右边不执行
| 对于符号两边的表达式都会执行, || 符号左边为true,则右边不执行
2、 & 、| 两边可以直接写数字, 按位计算 ,短路符号 不能直接运算数字
int a=1;
int b=2;
// System.out.println(a>b && b++>0); // 符号右边的不运算
// System.out.println("b:"+b);
System.out.println(a>b & b++>0); // 符号两边都运行
System.out.println("b:"+b);
// || 与 | 的区别
// System.out.println(a>=1 || a++<0); // a++ 不执行
// System.out.println("a:"+a);
System.out.println(a>=1 | a++<0 ); // a++ 会执行
System.out.println("再次输出a :" + a);
十进制转二进制
十进制 | 转换 | 二进制 |
---|---|---|
1 | 1*2的0次方 | 1 |
2 | 1*2的1次方 | 10 |
4 | 1*2的2次方 | 100 |
对于2的倍数 ,1*2的n次方 转成二进制位1后面n个0 | ||
16 | 1*2的4次方 | 10000 |
对于任意十进制转二进制,先查找比它小的且离它最近的2的倍数 ,然后差值再计算二进制 ,(使用拆分法)
例如 28 = 16+8+4 = 11100
34 = 32+2 = 100010
96 = 64+32 = 1100000
二进制转十进制
公式: 从个位开始,每个位上的数 乘以2的n次方 累加之和
100100 = 1*2的2次方+1 * 2的5次方 = 36
5、位运算符
移位运算符 | 说明 | 案例 |
---|---|---|
<< | 左移: 将一个数转成二进制之后,整体往左移动n位 ,扩大倍数 ,一个数向左移动n位,结果为这个数乘以2的n次方 | 3<<2 = 3*2的2次方 |
>> | 右移:将一个数转成二进制后,整体往右移动n位,缩小倍数,一个数向右移动n位,结果为这个数除以2的n次方(除不尽单独考虑) | 8>>2 = 8/2的2次方 |
> > > | 无符号的右移 ,不考虑符号位,将这个数整体王右移动n位。 | |
^n | 异或 | |
~n | 数值取反 |
//正整数的移位 << >> >>>
System.out.println(3<<2); // 12
System.out.println(7<<3); // 7*8=56
// 对于正数的无符号右移和 右移 结果一样
System.out.println(16>>2);// 4
System.out.println(18>>2);// 4
System.out.println(5^9);//12
System.out.println(3>>2);
System.out.println(3>>>2);
System.out.println(~5);
// 负数的移位
// 负数的左移位还是为负数
System.out.println(-4<<2); // -4*2的2次方 =
/**
* -4的原码: 1 0000... 00000100
* * -4的反码: 1 1111... 11111011
* * -4的补码: 1 1111... 11111100
* * 开始移位 2
* 1 1111... 11110000
* 最后结果 = 取反+1
* 1 0000... 00001111 + 1
* :
* 1 0000... 00010000 =-16
*/
// 补码 = 反码+1
//负数是对于补码 进行移位 -4/2 =-2
System.out.println(-4>>1);
// -16无符号右移2位
System.out.println(-16>>>2); //1073741820
// -16 的补码算出来
/**
* 原码 10000.. 0010000
* 反码 11111.. 1101111
* 补码 11111.. 1110000
* 00111.. 1111100 由于不考虑符号,移动后高位全部补0 变成正数
* 正数原码和补码一致 这个数即为所得
* 1073741820
*/
6、三目运算符
表达式 ? 结果1 : 结果2
当?前面成立时, 整个表达式输出 结果1 ,如果?前面不成立,则输出结果2
// 生成100以内的随机数
int n = (int)(Math.random()*100);
System.out.println("n:"+n);
System.out.println( n%2==0 ?"这个数是偶数":"这个数是奇数");
十一、表达式、语句块
表达式 : 通过运算符 和 操作数组成的 元素 , 表达式不能单独写在程序中,需要接受结果或输出。
表达式中可能同时存在多个操作符 ,此时需要考虑操作符的优先级问题
注意 : 这里的() 表示 方法的括号 ,点号表示小数点 ,[] 表示数组的下标
2-5 : 用于得到结果值
6-12:用于运算得到ture、false
13,14:是赋值 。赋值的优先级最低
语句块:
在一个方法中,可以使用{} 表示一个语句块 , 也可以放在方法的外面 ,类的里面,称为独立代码块
public static void main(String[] args) {
//定义一个方法中的代码块
{
// 局部变量只能使用在它所在的区域
int a=1;
a++;
System.out.println("这是一个方法里面的代码块 "+a);
}
// a++;
if(true){
System.out.println("这是一个if代码块");
}
}
十二、流程控制
1、定义
在一个Java程序中,各条语句的执行对程序的结果有直接影响,也就是说 各个语句的执行顺序对程序的结果有直接影响。
在程序中 ,可能出现不同的执行顺序,必须 自上而下顺序执行,或者 条件判断的顺序或者循环执行的顺序。
2、分类
顺序执行
条件分支
循环执行
3、顺序执行
//顺序执行, 从上而下执行
public static void main(String [] args){
System.out.println(1);
System.out.println(2);
System.out.println(3);
}
4、条件分支
1、if条件分支
语法:
if(条件){
语句块
}
其他代码
解释: 如果条件成立 ,则执行语句块 ,如果条件不成立,则不执行语句块
// 生成一个100以内的随机数 判断它是否为偶数
int n = (int)( Math.random()*100);
if(n%2 == 0){
System.out.println("这是数是偶数");
}
System.out.println("程序结束");
2、if…else条件分支
语法:
if(条件){
语句块1
}else{
语句块2
}
解释: 如果条件成立, 则执行语句块1 ,如果条件不能力 ,则执行语句块2
int n = (int)(Math.random()*100);
// n<50 需要买西瓜 >50 需要买葡萄
if(n<50){
System.out.println("买了一个大西瓜");
}else{
System.out.println("买了一串葡萄");
}
System.out.println("n->"+n);
System.out.println(" 嗯,程序猿的女朋友很高兴,至少买了水果");
3、if…else if … else 多条件分支
语法:
if(条件1){
语句块1
}else if(条件2){
语句块2
}else if(条件3){
语句块3
}
...
else{
语句块4
}
解释: 从条件1开始依次判断,如果条件1 成立,则执行语句块1 ,其他条件不再执行,如果条件2成立,则执行语句块2,其他条件不再执行。。。 依次类推如果条件都不成立,则执行else语句块。 ,最终只执行其中某一个语句块,
// 随机生成90以内的年龄 整数
int n = (int)(Math.random()*90);
if(n<18){
System.out.println("未成年");
}else if( n<30){
System.out.println("青年");
}else if( n<50){
System.out.println("中年");
}else if( n<70){
System.out.println("老年");
}else{
System.out.println("晚年");
}
System.out.println("n->"+n);
嵌套条件判断
语法: 以上3种格式 ,可以同时使用,在一个if语句再次嵌套if 语句
// 接收控制台输入 , 判断 输入的数 是否能被3整除
// 如果能被3整除,输出这个数除以3的结果,并判断结果能被7整除
// 如果不能被3整除,判断是否为偶数
Scanner sc = new Scanner(System.in);
// 接收控制台输入的整数
int n = sc.nextInt();
if(n%3 == 0 ){
System.out.println("这个数能被3整除");
// 在if语句中继续判断, 就是嵌套条件判断 ,需要往后缩进
int result= n/3;
if(result%7 == 0){
System.out.println("这个结果能被7整除");
}else{
System.out.println("这个结果不能被7整除");
}
}else{
System.out.println("这个数不能被3整除");
if(n%2 ==0){
System.out.println("这个数能2整除");
}else{
System.out.println("这个数不能被2整除");
}
}
注意 : 嵌套条件时 为了增强代码的可读性,将条件语句块的分支 往后缩进 ,{}作为一个整体
条件语句块中如果只有一个输出语句, 可以省略{}
5、选择条件判断
语法:
switch(表达式){
case 常量值1:
语句块1;
break; // 语句块接收的标记
case 常量值2:
语句块2;
break;
...
default:
语句块3;
break;
}
注意: switch 的表达式判断 只能等值比较 ,其中case的常量值 类型位: 整数型(byte short int long ),字符型,字符串型,枚举型
byte n = (byte)(Math.random()*7+1);
switch (n){
case 1 :
System.out.println("星期一");
break;
case 2:
System.out.println("星期二");
break;
case 3:
System.out.println("星期三");
break;
case 4:
System.out.println("星期四");
break;
case 5:
System.out.println("星期五");
break;
case 6 :
System.out.println("星期六");
break;
default :
System.out.println("星期天");
break;
}
case穿透问题
在switch中,如果case后面不写break,将会出现穿透现象,也就是说不会执行下一个case的判断条件直接往后运行,直到遇到break,或整体switch结束
练习
* 1、使用switch制作一个简单的计算器:
* 让用户输入计算数字1和运算符 及计算数字2,然后程序帮他计算出结果。
*
十三、循环
1、循环定义
在Java程序中,重复的执行某一段代码 这个过程称之为循环, 为了避免出现死循环,循环分为四部分
1、初始条件
2、循环的判断条件 ,条件为true ,则进入循环体
3、循环体
4、迭代变量
while循环
语法:
初始条件
while(判断条件){
循环体
迭代部分 (为了改变循环的判断条件)
}
计算1到100的累计之和 1+2+3+4…+100=?
初始值 n= 1
条件: 100以内的 数可以一直累加(一直循环)
迭代: n++
//计算 1到100的累加之和
int sum=0;
int n=1;
while(n<=100){
sum+=n;
n++;
}
System.out.println("n:"+n);
System.out.println("sum:"+sum);
do…while循环
语法:
初始值1
do{
循环体2
迭代部分3
}while(返回boolean类型的表达式4);
执行顺序: 123-》423 -》423-》423 .。。4 直到条件4为false 则退出循环。
先执行初始值 1,循环体2 ,迭代3
再判断条件4是否成立,成立,继续执行2,3
再判断条件4是否成立,成立,继续执行2,3
…
判断条件4是否成立,不成立,退出
int i=0;
do{
System.out.println("i--"+i);
i++;
}while(i<10);
System.out.println("i===="+i);
/**
* 第一遍: 输出 0 i=1
* 第二遍: 判断 1<10 成立 输出1 i=2
* 第三遍: 判断 2<10 成立 输出2 i=3
* .。。
* 第九遍: 判断8<10 成立 输出8 i=9
* 第十遍:判断 9<10 成立 输出9 i=10
* 第十一遍: 判断 10<10 不成立。退出
*
*
*/
问题: while循环与do while循环的区别?
1、while循环先判断条件是否成立,再执行循环体,do while循环 先执行一遍循环体再判断条件。
break : 退出循环
for循环
for循环的升级版就是 foreach循环
for循环通常在明确循环次数的情况下使用, 它也分为四部分
语法:
for(初始值1 ; 循环判断条件2 ; 迭代部分3 ){
循环体4
}
或者
初始值
for( ; 循环判断条件 ; ){
循环体
迭代部分
}
// 他们的区别是 初始值定义在for的外边,就可以在循环外边使用
循环执行流程:
1243-》243-》243-》243-》。。。》2 为false 循环退出
例如 :循环输出5遍hello world
// i 表示计数器,从1开始 到5结束
for(int i=1 ;i<=5 ; i++){
System.out.println("hello world");
}
循环的执行顺序:
第一遍: i=1 1<5 成立 输出“hello world ” i++ i=2
第二遍 :2<=5 成立 输出“hello world” i=3
第三遍 : 3<=5 成立 输出”hello world“ i=4
第四遍: 4<=5成立 输出”hello world“ i=5
第五遍: 5<=5 成立 输出”hello world“ i=6
第六遍: 6<=5 不成立,退出
i=6
使用for循环计算1-的阶乘
// 使用for循环 计算 10的阶乘
for(int i=1;i<=10;i++){
sum*=i;
}
for循环部分可以省略
// 死循环
for(;;){
System.out.println("hello");
}
for(;true;){
System.out.println("hello world");
}
// 迭代部分的代码 可以 放入循环体中
int i=0;
for( ; i<10; ){
System.out.println("第"+i+"次输出");
i++;
}
十四、关键字 break、continue 、return的区别
1、break : 用于在switch。。case中放置语句块穿透,
用于跳出循环
// 从1-100 遇到7的倍数 break
for(int i=1;i<100;i++){
// i==7 跳出循环
if(i%7 == 0 ){
break;
}
System.out.println(i);
}
2、continue: 跳出本次循环,继续下一次循环
for(int i=0;i<100;i++){
if(i%7 == 0 ){
continue; // 跳出本次循环,继续下一次循环
}
System.out.println("i---"+i);
}
3、return : 返回 本次方法
用法1 : 如果return放在循环中, 会跳出循环,且不会只想循环外面的语句 ,
用法2: 作为方法的返回值
用法3 : 无论方法是否有返回值 ,可以在条件判断的位置 直接 return ,
return和break在循环语句块是,break只是结束循环语句块,对于循环外面的代码会执行,而return是结束当前所在方法的剩下的语句块。
public static void main(String[] args) {
for(int i = 1;i<100;i++) {
if (i == 50) {
return;
}
System.out.println("i----"+i);
}
System.out.println("程序结束");
}
public void method1(){
// return 还可以在条件判断的位置 直接返回方法
int n = (int)(Math.random()*10);
if(n%2 ==0){
return ; // 方法的后面就不再运行
}
System.out.println("方法的其他代码块");
}
结论:只要执行return,那么它 后面的代码都不执行。
public int add(){
return 0;
}
return作为方法返回值的关键字 ,
十五、嵌套循环 以及案例
嵌套循环: 在一个循环语句中,还包含了另一个循环。例如 在一个for循环中还有一个for循环 ,
它的总的循环次数 = 外循环的次数* 内循环的次数
语法:
for(){ // 外层循环
for(){ // 内层循环
}
}
执行顺序: 外层循环 循环一次 ,内层循环循环完整的一遍
* * * * *
打印直角三角形
*
* *
* * *
* * * *
* * * * *
外循环控制打印几行, 内循环控制打印即可*
*
* * *
* * * * *
* * * * * * *
* * * * * * * * *
* * * * * * *
* * * * *
* * *
*
思路 : 考虑一行打多少个空格 多少个*
一共5 行 空格的个数(5-i) *的个数 (2 * i - 1)
i=1 4 1
i=2 3 3
i=3 2 5
i=4 1 7
i=5 0 9
System.out.println("打印正三角形");
for(int i=1;i<=5;i++){
// 先打印空格
for(int k=0;k<5-i;k++){
System.out.print(" ");
}
// 再打印*
for(int j=0;j<2*i-1;j++){
System.out.print("* ");
}
// 换行
System.out.println();
}
九九乘法表
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
....
1*9=9 2*9=18 ...... 9*9=81
十六、数组的概念以及数组案例
1、容器的概念
用于存储数据的一块内存称为容器,生活中有很多容器,例如 水杯,衣柜,书包,有一定的空间可以存放“东西”
存放在容器中的数据 称为“元素”
2、为什么会存在数组呢?
假如现在要存储全班同学的成绩 , 全班40人,按照定义变量的思维,需要定义40个double类型的变量,每次从40个变量中找某一个变量,操作很麻烦, Java中可以定义一个数据类型存放40个人的成绩 , 这个类型就是数组类型。
数组定义: 它是相同数据类型的有序集合
3、 数组特点
- 数组的长度固定(数组的长度一旦声明,就不能改变)
- 数组中存储的元素数据类型必须相同
- 数组的元素 通过下标访问,且下标默认从0 开始
- 数组类型属于引用数据类型, 数组的元素类型 既可以是基本数据类型,也可以是引用数据类型。
4、创建数组
方式一:
数组存储的数据类型 [] 数组名 = new 数组存储的数据类型[长度];
详解:
数组存储的数据类型 :创建数组容器中可以存储什么数据类型 (基本数据类型 ,引用数据类型)
[] : 表示数组
数组名: 给数组起给名字,遵循标识符规则
new : 创建数组的关键 字
[长度] : 数组的长度 , 这个长度定义后不可改变
例如
int [] arr = new int[3];
new出来的空间在堆内存中,数组是引用数据类型 ,存在内存地址
内存解析: 在堆内存中开辟一段连续的3个长度的int类型的内存空间 ,并由arr变量指向这块内存的地址 (换句话说 arr输出的就是 这个内存的地址)
方式二:
数据类型 [] 数组名 = new 数据类型[]{元素1,元素2,元素3...}
这里的数组长度根据元素的个数自动分配大小
int [] arr = new int[]{90,88,78,92};
或者
int arr [] = new int[]{90,88,78,92}
方式三:
数据类型 [] 数组名 = {元素1,元素2,元素3...};
注意: 这里的元素类型必须满足 数组的元素数据类型
char [] arr = {'a','b','c'};
或者
char arr [] = {'a','b','c'};
5、数组的访问
数组的访问通过索引访问
索引(下标): 每一个数组的元素都有一个编号,这个编号从0开始 , 这个编号称为数组的索引,通过数据名[索引] 访问到数组的原始
例如: 访问数组的第二个元素: 数组名[1]
数组的长度: 数组的长度 声明已固定 ,访问数组的长度 : 数组名.length
数组的最大索引= 数组的长度 -1
数组元素的赋值 :通过索引可以给元素赋值 数组名[索引] = 值
将数据 赋值给 指定索引的 元素
十七、方法
方法的概念
将一个功能抽取出来,放在类中的大括号中, 形成一个独立的功能 , 当需要使用该功能时,则调用它, 这样可以增强代码的复用性(重复利用) ,并解决代码的冗余现象。
方法的语法:
[访问修饰符] 返回值类型 方法名( [参数类型 参数名1 , 参数类型 参数名2 …] ){
方法体
}
详解:
访问修饰符: 用于修饰这个方法的调用范文 目前默认 public static
返回值类型: 无返回值就写void 或者 方法执行后返回的结果的数据类型 ,方法执行完之后会将结果返回
方法名 : 给方法取名, 准寻标识符的规则
参数类型 、参数名: 它们是同时定义 ,方法在执行时未知的数据,需要在调用方法时进行传递值。 参数类型表示 这个参数的数据类型 ,参数名就是一个参数名称 这个参数名可以在方法体中使用。
方法体: 这个方法具有的功能(代码块)
定义一个方法
public static int add(int num1 , int num2){
return num1+num2;
}
根据方法的参数 不同,返回值不同,可以将方法分为四类:
1、无参无返回值方法
语法:
public static void 方法名(){
方法体
}
2、无参有返回值方法
语法:
public static 返回值类型 方法名 (){
方法体
}
结果在n中
3、有参无返回值方法
语法:
public static void 方法名(参数列表 ){
方法体
}
情况一、 当参数中是基本数据类型 ,将实参的值赋值给 形参
public static void add(int num){
num++;
System.out.println("方法中 num 的值:"+num);
}
调用方法: num的改变不会改变n 的值 ,因为是两个独立的内存
int n =10;
System.out.println(n);
add(n);
System.out.println("方法外面 实参的值:"+n);
结果输出:
方法中 num 的值: 11
方法外面 实参的值:10
情况二: 当参数的数据类型是引用数据类型
例如 数组 、类
// 方法的比对 参数是数组
public static void add(int [] arr){
arr[0]++;
System.out.println("方法中 arr[0]="+arr[0]);
}
调用:
int [] array ={10,20};
add(array);// 会调用 参数是数组的add方法
System.out.println("方法外面的 arr[0]="+ array[0]);
结果:
方法中 arr[0]=11
方法外面的 arr[0]=11
类的调用:
public static void addAge(Student student){
// 将学生的年龄 获取 自加
int age = student.age;
age++;
// 在重新赋值
student.age=age;
}
调用
Student student = new Student(); // age默认为 18
System.out.println("方法调用之前: "+student.age); // 18
addAge(student); // 传的地址
System.out.println("方法外面 学生的年龄:"+student.age);
结果输出: 方法调用之前: 18
方法外面 学生的年龄:19
/**
* 以上方法调用 的结论: 对于参数为引用数据类型,方法外面和方法内部公用同一块内存,
* 也就是说 参数再传递时,将引用类型的地址赋值给 方法的形参
* 对于基本数据类型 ,方法的参数将 值的副本赋值给形参,这样形参的改变
* 不会影响实参的值
* 原因: 引用数据类型在参数传递时 是地址 (JVM对于堆内存的大小不可控)
* 基本数据类型在参数传递时 是值
*
*/
情况三、 当参数是String类型时 ,String是引用数据类型 ,但是在参数传递时,是与基本类型一样
public static void main(String[] args) {
// 参数是字符串
String uname ="张三";
sayHello(uname);
System.out.println("我最后对"+uname+"sayHello");
}
public static void sayHello(String name){
name="李四";
System.out.println("我对"+name+"sayHello");
}
结果:
我对李四sayHello
我最后对张三sayHello
4、有参有返回值方法
语法:
public static 返回值类型 方法名(参数列表){
方法体
}
例如 :
public static String sayHello(String name){
name="李四";
System.out.println("我对"+name+"sayHello");
return name ;
}
调用
public static void main(String[] args) {
// 参数是字符串
String uname ="张三";
// 将返回值接收 ,这是 uname 才被改变 ,如果不接受,则不改变
uname = sayHello(uname);
System.out.println("我最后对"+uname+"sayHello");
}
结果:
我对李四sayHello
我最后对李四sayHello