package cn.ideal.javase;
/**
* @Description: HelloWorld
* @Author:BWH_Steven
* @Date: 2021/8/30 3:03 下午
*/
public class HelloWorld {
public static void main(String[] args) {
System.out.println("HelloWorld !");
}
}
上面的代码,就是一个最简单的 Java 程序 —— HelloWorld,它也是梦开始的地方。
别看程序虽小,但是五脏俱全,package、public、class、static 关键字, /** */ 类注释,HelloWorld 类名,main 主函数,println() 输出打印方法,"HelloWorld !" 关键字。各个不同的语法结合,就构成了这个入门的程序。
如果看不明白,没关系,这就是这一篇文章想要讲解的。
1. 关键字关键字是被Java语言赋予特定含义的单词,他们有着特定的使用位置和方式。
注意:
-
关键字全都是小写。
-
goto 和 const 作为保留字存在。
-
常见的 IDE 如 IDEA、Eclipse,以及 Noepad++、Sublime Text 等编辑器对关键字有特殊颜色标记,这也是人们常说的代码高亮。
列举:
虽然下面表格中,你或许大部分关键字都没有见过,这里不必细究其含义,也不必去刻意记忆,因为后面都会涉及到,但是你只需要记住一点:下面表格中 接近 100% 的关键字将会陪伴你的 Java 生涯!
类别 | 关键字 |
---|---|
private | 私有的 |
protected | 受保护的 |
public | 公共的 |
abstract | 声明抽象 |
class | 类 |
extends | 扩充,继承 |
final | 最终值,不可改变的 |
implements | 实现(接口) |
interface | 接口 |
native | 本地,原生方法(非Java实现) |
new | 新,创建 |
static | 静态 |
strictfp | 严格,精准 |
synchronized | 线程,同步 |
transient | 短暂 |
volatile | 易失 |
break | 跳出循环 |
case | 定义一个值以供switch选择 |
continue | 继续 |
default | 默认 |
do | 运行 |
else | 否则 |
for | 循环 |
if | 如果 |
instanceof | 实例 |
return | 返回 |
switch | 根据值选择执行 |
while | 循环 |
assert | 错误处理,断言表达式是否为真 |
catch | 捕捉异常 |
finally | 有没有异常都执行 |
throw | 抛出一个异常对象 |
throws | 声明一个异常可能被抛出 |
try | 捕获异常 |
import | 引入包 |
package | 包 |
boolean | 布尔型 |
byte | 字节型 |
char | 字符型 |
double | 双精度浮点 |
float | 单精度浮点 |
int | 整型 |
long | 长整型 |
short | 短整型 |
super | 父类,超类 |
this | 本类 |
void | 无返回值 |
goto | 保留关键字,是关键字,但不能使用 |
const | 保留关键字,是关键字,但不能使用 |
null | 空 |
标识符就是给类,接口,方法,变量等起名字的字符序列。
-
PS:这几个概念不熟悉没关系,这一篇和下一篇会依次讲到。
组成规则:
-
首字符:字母(
A-Z、a-z
)、美元符($
)、下划线(_
) -
首字符之后:字母(
A-Z、a-z
)、美元符($
)、下划线(_
)或者数的任何字符组合
注意事项:
-
区分大小写
-
不能以数字开头
-
关键字不能作为标识符
组成规范:
命名规范是我们不得不提的一个话题,虽说命名本应该是自由的,但是仍然有一定的“潜规则”,通过你对命名的书写,别人一眼就能看出你是不是一个“行家”。而且往往这些规范,能巧妙的帮助我们规避很多潜在的风险。
-
例如 《阿里巴巴 Java 开发手册》《代码整洁之道》等都对命名做出了不同程度的限制推荐。
下面的引用来自 《阿里巴巴 Java 开发手册》:
3. 注释 3.1 定义
【强制】所有编程相关命名均不能以下划线或美元符号开始,也不能以下划线或美元符 号结束。
反例:name / __name / Object / name / name/ Object
【强制】所有编程相关的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。说明:正确的英文拼写和语法可以让阅读者易于理解,避免歧义。注意,即使纯拼音命名方式也要避免采用。
反例:DaZhePromotion [打折] / getPingfenByName() [评分] / int 变量 = 3;
正例:ali / alibaba / taobao /cainiao / aliyun / youku / hangzhou 等国际通用的 名称,可视为英文。
注释就是对程序进行解释说明的文字(不会被编译运行)
其目的是为了方便自己或别人后期阅读这部分代码的提示,能够快速的让阅读者了解这部分代码的作用。
当你需要维护一个老项目的代码时,几万甚至几十万行的代码量非常常见,除了相对规范的包结构和文档能把你带到入口处(前后端接口),如何去梳理业务的逻辑就大大的依赖你的技术经验和前人的注释了。
虽然有个梗:“只要我的代码谁也看不懂,我在公司就是不可或缺的”,不过这句话图个乐就得了,如果不养成良好的习惯,以后团队协作和提交前/日后 review 代码就会变得异常折磨。
-
单行注释
// 这行注释
-
多行注释
/*
uid 用户id
name 姓名
age 年龄
*/
-
文档注释(JavaDoc 注释)如下:
类注释
/**
* @Description: HelloWorld
* @Author: BWH_Steven
* @Date: 2021/8/30 3:03 下午
*/
方法注释
/**
* 用户消息查看
*
* @param req SearchUserMsgReq 请求参数
* @return List 封装DO的List
*/
编写代码时,类注释和方法注释都必须使用 JavaDoc 注释,而不是 // 这种单行注释,类能看到作者以及描述创建时间,方法能不进入代码块的情况下方便的看到方法描述和参数以及返回值。
4. 常量 4.1 定义常量就是在程序执行的过程中,其值不发生改变的量(例如π、重力加速度,光速等)
在 Java 中我们使用 final 关键字来修饰常量
-
eg: final double PI = 3.1415927
注意:虽然常量名也可以用小写,但为了便于识别,通常使用大写字母 表示常量,这也算是大家默认的要求。
4.2 怎么用?一般来说,我们写代码时,是不允许出现魔法值的(即未预先经过定义的值)
例如根据 id 查询用户的昵称和头像时,如果查询不到,则给一个默认值,避免直接返回 null。
// 例如 userInfo 就是查询到的用户信息
if (userInfo == null || StingUtils.isBlank(userInfo.getUserName)){
userInfo.setUserName("用户");
}
像 userInfo.setUserName("用户"); 中的 "用户" 就是魔法值,因为我们并没有事前定义它,所以可以定义一个常量类,其中使用 final 修饰我们想定义的常量。
public class DefaultInfoConstant {
public static final String DEFAULT_PERSON_HEAD_IMAGE_URL = "xxx.png";
public static final String DEFAULT_USER_NAME = "用户";
}
这样就可以这样调用了,以后所有调用了这个常量的部分我们都不需要去 *** 心了,修改这个常量类即可,所有引用它的地方都会跟着变化了。
// 例如 userInfo 就是查询到的用户信息
if (userInfo == null || StingUtils.isBlank(userInfo.getUserName)){
userInfo.setUserName(DefaultInfoConstant.DEFAULT_USER_NAME);
}
5. 变量
5.1 定义
我们刚介绍了什么是常量,那么什么是变量呢,顾名思义,变量就是在某个范围内可以变化的量,其实它就是一个被你所定义的变量,在一个数据类型的约束下,可以在数据类型所允许的范围内进行,被赋值,运算,等 *** 作。
image.png
格式:数据类型 变量名 = 初始化值
注意:可以在一行中声明多个变量,但是我们不推荐这种方式。
尤其真实项目中往往变量名会比较长,逐一声明变量能提高程序的可读性。
// 不推荐
String name, address;
// 推荐
String name;
String address;
5.2 变量类型
-
局部变量
-
实例变量
-
类变量(静态变量)
局部变量就是定义在方法、构造方法、或者语句块中的变量
public class HelloWorld {
public static void main(String[] args) {
// 下一行的 name 会报错
System.out.println(name);
}
public static void testMethod() {
String name = "张三";
}
}
局部变量即只能在一定范围内使用的变量,随着这个方法/语句块的结束,这个变量也就无效了。(生而带来,死而带去 只能活在自己的世界),所以上述代码中,我们在 testMethod 方法中定义了 name 字符串,其值为 "张三",但是这也就意味着这个变量的作用域只在 testMethod 方法中,自然不能在别的地方,例如 main 函数中去调用了。
PS:对于局部变量的理解,刚入门可能也不会太深,等后面几篇我们学习到方法后,再回过头来看这部分内容,就会有一种明了的感觉。
5.2.2 实例变量实例变量:声明在类中,但在方法、构造方法和语句块之外
public class Student {
private String name;
private int age;
public void print(){
System.out.println("print: " + name + ", " + age);
}
}
实例变量对于类中的方法、构造方法或者语句块是可见的。一般情况下应该把实例变量设为私有。通过使用访问修饰符可以使实例变量对子类可见。例如文中的 name 和 age 就都是实例变量,在同一个类中的 print 方法中是可以直接访问的,同时利用 private 控制了变量的可访问范围。
暂时在学习基础语法知识的时候可以暂时忽略实例变量这部分内容,这部分内容主要被使用在面向对象的部分,但是极其重要。
5.2.3 类变量static 修饰的变量也称作静态变量,静态变量属于类,所以也称为类变量,存储于方法区中的静态区,随着类的加载而加载,消失而消失,可以通过类名调用,也可以通过对象调用。
例如在 Student 类中定义两个 public 修饰的变量 name 和 address,而且其中 name 是用 static 修饰的,即是一个类变量。
public class Student {
public static String name;
public String address;
}
当我们在另一个类中去调用这个变量的时候,只有 name 可以用类名调用。而 address 就必须创建对象后才能调用。(这部分后面的文章会讲到)
public class Demo {
public void testMethod() {
// 可以用类名调用
String name = Student.name;
// 不可以
String address = Student.address;
}
}
6. 数据类型
6.1 定义
Java是一种强类型的语言,针对每一种数据都定义了明确的数据类型(就是将一些值的范围做了约束,从而为不同类型的值在内存中分配不同的内存空间)
注意:在此部分暂时不用深究引用类型,着重认熟悉一下基本数据类型,引用类型在面向对象的部分会详细解释。
我们来看一下八种基本数据类型的详细说明:
Name | Size* | Rang |
---|---|---|
byte | 1byte | 8bit |
short | 2bytes | 16bit |
int | 4bytes | 32bit |
long | 4bytes | 64bit |
float | 4bytes | 32bit |
double | 8bytes | 64bit |
boolean | 只有true和false两个取值。 | |
char | 2bytes | 存储Unicode码,用单引号赋值。 |
注意:
-
整数默认是 int 类型。
-
声明 long 型常量的时候长整数要加 L 或者 l。
-
一些字体下 1 和 l 容易混淆,所以规范书写,都加大写 L。
如:long l = 66666666666666L; // 否则报错
-
浮点数默认是 double(双精度浮点型)。
声明 float 型(单精度的浮点数)要加 F 或者 f。
double d = 521.1;// double 不需要加字符
float f = 52.1f; // float 必须加f
-
boolean 一般用来进行逻辑运算 - 流程控制中。
-
byte、short 类型被赋值时,其实接收的是一个 int 类型的值,不在范围内即报错。
-
一个中文字符占据两用字节,Java中字符可以存储一个汉字,是因为Java字符采用Unicode编码,每个字符占用两个字节。
-
Java中提供了三个特殊的浮点数值,正无穷大(正数除以 0),负无穷大(负数除以0),NaN(不是一个数字,0 除以 0,负数开根号)。
一般来说,我们在运算的时候,要求参与运算的数值类型必须一致,很多时候就需要进行数据类型的转换。类型的转换大致分为两种:
-
默认转换
-
强制转换
默认转换就是从小类型转换为大类型的自动类型转换。
-
这个大小是按照它们各自代表的数据存储范围来的。
-
排序如下:byte、short、 char、 int、 long、float、double
-
int → long → float → double 这几者可以按顺序转换,而 byte,short, char 相互之间不转换。
举个例子:int 类型的 520 可以被 long 类型的变量接收,然后输出。
public static void main(String[] args) {
int numInt = 520;
long numLong = numInt;
System.out.println(numLong);
}
疑惑:为什么 float(4个字节)在 long(8个字节)后面?
-
它们底层的存储结构不同
-
float 表示的数据范围比long范围要大
long:2^63-1
float:3.410^38 > 210^38 > 28^38 > 22^3^38
= 2*2^144 > 2^63 -1
正例:低精度byte到高精度int 会根据默认转换,自动转换类型
反例:高精度int到低精度byte 可能会损失精度
public class Demo {
public static void main(String[] args) {
byte a = 3;
int b = 4;
byte c = a + b;
System.out.println(c);
}
}
image.png
byte 数据类型是 1个字节、8位
int 数据类型是 4个字节、32位
但是有没有办法能够让我们输出这种运算的结果呢?这就需要我们用到强制类型转换的知识。
格式:目标数据类型 变量 = (目标数据类型)被转换的数据
int i = 128;
// 格式如下
byte b = (byte)i;
注意:
-
在把容量大的类型转换为容量小的类型时必须使用强制类型转换。
-
不要随便的去用强制转化,因为它隐含了精度损失的问题。
-
如上述代码:因为 byte 类型是8位,最大值为 127,所以当 int 强制转换为 byte 类型的时候,值 128 就会导致溢出。
来看两个例子:
6.2.2.1 例子:变量相加赋值和常量相加赋值
public static void main(String[] args) {
byte b1 = 3;
byte b2 = 4;
byte b;
// 下面两个赋值有什么区别吗
b = (byte) (b1 + b2);
b = 3 + 4;
System.out.println(b);
}
第一个赋值语句:
-
byte 类型的 b1,b2 相加,自动类型转换为 int 型,int 类型的(b1 + b2) 赋值给 byte 类型的 b,属于大单位转换为小单位 可能造成精度损失。
第二个赋值语句:
-
3 和 4 为常量,编译过程中 先把结果计算出来,然后看是否在 byte 的范围内,如果在就不报错。
总结:
-
变量相加,会首先看类型问题,最终把结果赋值也会考虑类型问题。
-
常量相加,首先做加法,然后看结果是否在赋值的数据类型范围内,如果不是,才报错。
再配合下一个例子,大家就能深刻的理解丢失精度的意义了。
6.2.2.2 例子:强转后丢失精度
public static void main(String[] args) {
byte b = 130;
byte b = (byte) 130;
System.out.println(b);
}
-
当你打出
byte b = 130;
时,编译器应该已经在代码处报红了,因为 byte 的范围是:-128 到 127,所以报错了。 -
它下方的
byte b = (byte) 130;
使用了强制类型转换却不会报错,并且能输出结果 -126。
分析(原反补码将在下面具体介绍)
我们想要知道结果是什么,就应该知道是如何计算的,而我们又知道计算机中数据的运算都是补码进行的。
得到补码,首先要计算出数据的二进制,如下,求出130的二进制 10000010
130 是一个整数 所以补齐4个字节 (一个字节8位)
0000000 00000000 00000000 10000010
接着做截取 *** 作,截成 byte 类型的 10000010,而这个结果是补码,如下表已知补码求原码,最后的结果是 11111110 转换为十进制为 -126
值位 | 符号位 | 数值位 |
---|---|---|
补码: | 1 | 0000010 |
反码: | 1 | 0000001 |
原码 | 1 | 1111110 |
字符是指在计算机中所使用的 字母、数字、汉字、和符号,表示时用单引号包含在内。例如:'5' 和 'R' 和 '和' 均是字符
在内存中,字符数据以ASCII码存储 ,即以整数表示
需要记忆的常见字符 'a' → 97 'A' → 65 '0'→ 48,其余字符依次递推即可
值 | 符号 | 值 | 符号 | 值 | 符号 | 值 | 符号 | |
---|---|---|---|---|---|---|---|---|
0 | 空格符 | 42 | * | 62 | 123 | > | 32 | { |
空格 | 43 | + | 63 | ? | 124 | | | 33 | |
! | 44 | , | 64 | @ | 125 | } | 34 | |
" | 45 | - | 65~90 | A~Z | 126 | ~ | 35 | |
# | 46 | . | 91 | [ | 127 | Delete 键 | 36 | |
$ | 47 | / | 92 | 37 | ||||
% | 48~57 | 0~9 | 93 | ] | 38 | |||
& | 58 | : | 94 | ^ | 39 | |||
' | 59 | ; | 95 | - | 40 | |||
( | 60 | < | 96 | ` | 41 | |||
) | 61 | = | 97~122 | a~z |
有一些特殊的字符叫做转义字符,其格式为通过
转义 + 字符 = 转移字符 = 转变含义的字符(不再是本来字符的意思)
意义 | ASCII码值(十进制) | \a | |
---|---|---|---|
响铃(BEL) | 007 | \b | |
退格(BS) ,将当前位置移到前一列 | 008 | \f | |
换页(FF),将当前位置移到下页开头 | 012 | \n | |
换行(LF) ,将当前位置移到下一行开头 | 010 | \r | |
回车(CR) ,将当前位置移到本行开头 | 013 | \t | |
水平制表(HT) (跳到下一个TAB位置) | 009 | \v | |
垂直制表(VT) | 011 | \ | |
代表一个反斜线字符''\' | 092 | \' | |
代表一个单引号(撇号)字符 | 039 | \" | |
代表一个双引号字符 | 034 | \? | |
代表一个问号 | 063 | 空字符(NUL) | |
000 | \ddd | 1到3位八进制数所代表的任意字符 | |
三位八进制 | \xhh | 十六进制所代表的任意字符 | |
十六进制 |
举个例子,例如 \n 就是换行的意思:
\n
输出的结果是这样的(要注意,我当前是基于 macbook 演示的):
\n
6.3.2.1 \r和 \n的区别
回车 \r 意思是光标重新回到本行的开头,换行 \n 表示光标移动到下一行,不一定是行首,取决于其后是否还有内容。(因为我们常用在一行的句末,所以会误以为会在下一行的行首)
针对不同系统换行符也不同:苹果系统Mac \r\n
,Unix、Linux系统 public static void main(String[] args) {
// 输出 Hello1
System.out.println("Hello" + 'a' + 1);
// 输出 98Hello
System.out.println('a' + 1 + "Hello");
// 输出 5 + 5 = 55
System.out.println("5 + 5 = " + 5 + 5);
// 输出 10 = 5 + 5
System.out.println(5 + 5 + " = 5 + 5 ");
}
,Windows系统 int x = 3;
int y = 4;
System.out.println(x/y); →System.out.println(x * 1.0 / y );
在Wwindows 中,如果在两端字符串的中间使用转义字符,只有使用 \r\n才能真正的达到了我们日常 *** 作中,回车换行的那种效果。
注:虽然字符串并不是一个基本数据类型,但是因为这里讲解的比较简单,所以直接跟在字符类型下面做个比对好了。
字符串(String)是由零个或者多个字符组成的有限序列,它是编程中表示文本的数据类型,字符串使用的时候用双引号括起来即可,而且 String 并不是 Java 中的基本方法,而是一个类。
我们在此部分不做过多的介绍,但要知道,String类是一个非常非常重要的类!!!
我们会在后面有专门一大篇介绍
下面举几个例子简单看一下:
int x = 4;
int y = ( x++ ) + ( ++x ) + ( x * 10);
System.out.println( y );
首先 x 后置++ 所以括号1中 x运算时取4 然后自增为5
其次 x前置++ 所以括号2中 x = 6
最后 x * 10 = 6 * 10 = 60
Output y → 4 + 6 + 60 = 70
大家可以看看是不是和自己想象中的输出值是一致的
-
字符串和其他数据做加法运算的时候,结果是字符串类型。
-
这里的 + 不是加法运算,而是字符串连接符。
说道运算符,大家能想到最简单的就是加减乘除了,是的它们就是运算符中的算数运算符,而运算符其实就是用于执行程序代码运算的,通过运算符,能够实现计算、比较、赋值等多种运算效果。
常见的运算符类型:算数运算符、赋值运算符、比较运算符、逻辑运算符、位运算符、三目运算符。
算数运算符有:+ - * / % ++ --
-
加减乘除就不谈了,我们谈谈几个需要注意的点。
-
整数相除只能得到整数,如果有小数它会把小数位舍弃掉(想得到小数 需将其中任意的一个数据变成浮点数)
public static void main(String[] args) {
// 定义一个变量
int x = 520;
// 和 x = x + 520 是等价的
x += 520;
// 输出
System.out.println(x);
}
-
**/ **是除法求商 **% **是除法取余
-
++, -- 就是对变量进行自增 1 或者自减 1 ,而且 参与运算 前置后置有区别
public static void main(String[] args) {
short s = 1;
s = s + 1; // ①
s += 1; // ②
System.out.println(s);
}
7.2 赋值运算符
基本的赋值运算符:=
扩展的赋值运算符:+=,-=,*=,/=,%=
public static void main(String[] args) {
int a = 10;
int b = 20;
boolean flag = (a == b);
System.out.println(flag);
}
首先,基本的赋值运算符就是将等号右侧的值赋予给左边定义的变量,这样当你去调用 x 就知道整型类型的变量 x 的值现在等于 520
而 += 这些 *** 作其实都是一些简化的扩展,例如代码中 x += 520 就相当于 x = x + 520,就是在自己本身的基础上进行加减乘除某个值,就可以写成这种形式。
既然这两种形式相同,那么代码中 ① 和 ② 的执行结果相同吗?
原码
结果是否定的,代码编译到 s = s + 1 这句的时候就会报错了
image.png
但是直接去编译第二个语句,其实不会报错的:
扩展的赋值运算符其实隐含了一个强制类型转换
s += 1;不是等价于 s = s + 1 而是等价于 s = (s的数据类型) (s + 1);
经常我们需要比对两个值的关系,例如比较是否相等,谁大谁小。而这种关系正好契合 布尔类型 boolean,即只有 true 和 false 两种情况,用来比较符号就是关系运算符,它有这几个:==, !=, >=, <, <=
正数的原码最高位是0的原码最高位是1其他的是数值位
输出:false
7.4 逻辑运算符逻辑运算符用于连接布尔型表达式,常见的逻辑运算符有:& | && || !
-
例如在java中,不可以写成 3 < x < 6 应该写 成 x > 3 & x < 6
问题:&& 和 & 的区别?同理 || 和 | 的区别
-
最终结果一样
-
&& 具有短路作用,只要左边是 false,右边就不执行。(&&效率更高)
| *** 作符 | 描述 | 例子 |
| --- | --- | --- |
| && | 称为逻辑与运算符。当且仅当两个 *** 作数都为真,条件才为真。| (A && B)为假。|
| | | | 称为逻辑或 *** 作符。如果任何两个 *** 作数任何一个为真,条件为真。| (A | | B)为真。|
| !| 称为逻辑非运算符。用来反转 *** 作数的逻辑状态。如果条件为true,则逻辑非运算符将得到false。| !(A && B)为真。|
位运算在前期看来,似乎用处并不是很大,但是当你后面去看一些源码,自己造一些轮子的时候,就知道位运算的重要了。而学习位运算,就必须补充原码、反码、补码的知识。
7.5.1 原码、反码、补码为什么我们要学习这些呢?首先我们要知道,在计算机内,有符号数有三种表示方法,原码、反码、和补码。而所有的数据运算都是采用补码进行的。它的重要性可想而知。
-
原码:二进制点表示法,最高位为符号位,“0”表示正,“1”表示负,其余位置表示数值大小,可直观反映出数据的大小。
-
反码:解决负数加法运算问题,将减法运算转换为加法运算,从而简化运算规则。
-
补码:解决负数加法运算正负零问题,弥补了反码的不足。
举个例子:7的二进制 :111
符号位 | ||
数值位数 | +7 | 0 |
0000111(补够8个字节,在左面补4个0) | -7 | 1 |
0000111 | 反码 | 正数的反码与原码相同负数的反码与源码符号位相同,数值位取反1 → 0 、 0 → 1 |
符号位 | ||
数值位数 | +7 | 0 |
0000111(补够8个字节,在左面补4个0) | -7 | 1 |
1111000 | 补码 | 正数的补码与原码相同负数的补码是在反码的基础上+1 |
符号位 | ||
数值位数 | +7 | 0 |
0000111(补够8个字节,在左面补4个0) | -7 | 1 |
1111001 |
7.5.2 位运算符
(3 & 4) (3 | 4) (3 ^ 4) (~3) (3 << 2) (>>) (>>>)
因为是位运算,所以我们需要把数据换算成二进制
00000000 00000000 00000000 00000011
& 00000000 00000000 00000000 00000100
------------------------------------------
00000000 00000000 00000000 00000111
结果是 7
&位与运算:有 0 则 0
00000000 00000000 00000000 00000011
& 00000000 00000000 00000000 00000100
------------------------------------------
00000000 00000000 00000000 00000111
结果是 7
&位与运算:有 1 则 1
00000000 00000000 00000000 00000011
& 11111111 11111111 11111111 11111100(补码)
补码:11111111 11111111 11111111 11111100
反码:11111111 11111111 11111111 11111011
原码:10000000 00000000 00000000 00000100
结果是 -4
^位异或运算:相同则 0,不同则 1
-24 的二进制为 -11000
原码:10000000 00000000 00000000 00011000
反码:11111111 11111111 11111111 11100111
补码:11111111 11111111 11111111 11101000
右移:0011111111 11111111 11111111 111010(00)
结果是 1073741818
~按位取反运算符:0 变 1,1 变 0
-
宏观表现:本身的相反数 - 1
// 方式1:使用一个中间传递变量(开发中常用)
c = a;
a = b;
b = a;
// 方式2:用位异或实现
a = a ^ b;
b = a ^ b; // b = a ^ b ^ b = a
a = a ^ b; // a ^ b ^ a = b
// 方式3:用变量相加的做法
a = a + b;
b = a - b;
a = a -b;
// 方式4:一句话的事
b = (a + b) - (a = b)
<< 按位左移运算符,左操作数按位左移右操作数指定的位数(左边最高位丢弃,右边补齐 0)
-
宏观表现:把 << 左边的数据乘以 2 的移动次幂
-
3 << 2 等于 3 * 2^2 = 3 * 4 = 12
>>
按位右移运算符,左 *** 作数按位又移右 *** 作数指定的位数(最高位是 0,左面补齐0;最高位是 1,左边补齐 1)
-
宏观表现:把 >> 左边的数据,除以 2 的移动次幂
-
-24 >> 2 等于 -24 / 2^2 = -6
>>>
按位右移补 0 运算符,无论最高位是 0 还是 1,左边补齐 0
-
宏观表现:正数和 >> 效果是一致的,负数得原反补右移等计算出来
-
24 >>> 2 等于 24 >> 2 = 6
-
-24 >>> 2 需要位计算
将a,b 中的较小数赋值给x
x = a < b ? a : b
// 两者等价
if (a < b) {
x = a;
} else {
x = b
}
7.5.3 例题
-
你有多少种交换两个整型数的方法?
-
补充:^的特点:一个数据对另一个数据位异或两次,该数本身不变
if (比较表达式) {
语句体;
}
-
请用最有效的方式写出计算2乘以8的结果?位运算的效率高于十进制运算
-
2 * 8
-
2 << 3
这一部分要与下面马上要学习的if语句进行对照学习
满足表达式则执行冒号前的表达式,反之则时候后面的
格式 :(条件表达式)?(条件真的表达式):(条件假的表达式)
-
条件表达式:结果是一个boolean型
if (比较表达式) {
语句体1;
} else {
语句体2;
}
8. 键盘录入
就 Java 基础而言,大部分 *** 作都是在控制台中的,所以当你想进行一些交互的时候,大部分都是依赖于键盘的输入,所以这里也需简单的提及一下:
-
我们之前所写的程序中,数据的值都是固定的,在源码中就写好的,而我们有时候想要让用户来决定一些值的具体数据(例如:学生成绩录入),所以键盘录入就是让用户输入一些值,使得程序更加灵活。
现在我们对于导包以及对象的概念仍然比较模糊,但是我们在介绍别的知识的时候也会频繁的用到,所以大家暂时按照以下的格式记忆下来。
-
A:导包:
-
格式:import java.util.Scanner;
-
位置:在class上面
-
B:创建键盘录入对象
-
格式:Scanner sc = new Scanner(System.in);
-
C:通过对象获取数据
-
格式:int x = sc.nextint();
-
String s = sc.nextLine();(字符串录入)
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("first");
int a = sc.nextInt();
System.out.println("second");
int b = sc.nextInt();
int max = ((a > b) ? a : b);
System.out.println(max);
}
9. 选择结构(分支结构)
分支结构就是能让我们的程序根据判断条件,在不同的情况下,执行不同的逻辑,主要的选择结构有 if 和 switch 两个。
9.1 if 语句使用 if 后,圆括号内的部分就是你想设定的条件,其中会计算出一个布尔值,例如 if (a > b) ,如果结果为 true 就执行语句体,不执行就出去。
而如果想为 true 就执行语句体1,为 false 就执行语句体2,就可以使用 if else 这个结构,它适用于两种情况都分别处理的情况。
第三种情况更加多样,它允许你指定多个 if 条件,从第二个开始用 else if 表示,只有当 if 中的条件全部不满足时候,才会执行 else
if (比较表达式) {
语句体1;
} else if (比较表达式2) {
语句体2;
} else if (比较表达式3) {
语句体3;
} else {
语句体4;
}
switch(表达式) {
case 值1:
语句体1;
break;
case 值2:
语句体2;
break;
...
default:
语句体 n + 1;
break;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("input your score");
int score = sc.nextInt();
score = score / 10;
switch (score) {
case 9:
System.out.println("very good");
break;
case 8:
System.out.println("good");
break;
case 7:
System.out.println("ok");
break;
case 6:
System.out.println("just so so");
break;
default:
System.out.println("once again");
}
}
这里有几个点要说明一下:
-
有的小伙伴可能学习过 C++ 等语言,可能它们条件后的左大括号都是换行的,这其实只是代码风格问题,一般 Java 来说,都是左大括号跟在括号后面。有具体需要也可以选择任意风格,不过最好团队统一。‘
-
尽可能避免各种嵌套 if,除非必须这样,否则代码会看起来很混乱。
-
三元运算符可以使用 if 语句进行改进,但是反之则不成立,当if语句控制的语句体是一条输出语句的时候,就不成立,因为三元运算符是一个运算符,必须要求有一个结果返回,而输出语句却不能作为一个返回结果。
switch 语句也是一种选择结构,并且在一些情况下看起来更加简洁明了。
for(初始化语句, 判断条件语句, 控制条件语句){
循环语句
}
格式解释:
-
switch:表示这是个 switch 选择结构。
-
表达式:此处的取值是有限制的,例如 byte short int char 等,JDK5后还可以是枚举,JDK7 后可以是字符串。
-
case:case 后跟的值跟的是要和表达式进行比较的值。
-
语句体:满足这个 case 后要执行的代码。
-
break:表示终端,结束的意思,可以控制 switch 语句的结束。
-
default:当所有 case 都不满足,则执行它的语句,相当于 if 语句中的 else
注意:
-
case 后面只能是常量,不能是变量,而且不能出现相同的 。
-
default 可以省略 但是一般不建议,除非判断的值是固定的,单选题。
-
break 可以省略,一般不建议 。
-
defaul t可以出现在 switch 语句的任意位置 。
-
switch 语句的结束条件:遇到 break 或者执行到程序的末尾。
以下条件选用switch:
-
条件分支有多个 。
-
条件的值是整数或一个字符型 。
原因:
-
如果条件分支太多时用 if 语句,一定会出现 if 的嵌套,if 嵌套的越多,程序 的开销就会随着增大,这样整个程序的运行效率就一定会大大降低。
-
switch 值比较一次就可以找出条件的结果 。
举例:
public static void main(String[] args) {
int sum1 = 0;
for (int x = 1; x <= 10; x++){
sum1 += x;
}
System.out.println("sum(1-100): " + sum1);
System.out.println("--------------------");
int sum2 = 0;
for (int x = 1; x <= 100; x++){
if(x % 2 == 0){
sum2 += x;
}
}
System.out.println("sum(1-100): 偶数和" + sum2);
}
10. 循环语句
循环语句,顾名思义就是把一些代码,按我们要求的次数,多次循环执行,例如需要重复执行的语句等等。主要有三种:for 循环、while 循环、do…while 循环。
10.1 for 循环 10.1.1 定义for 循环堪称最常见的循环了,它不仅适用于循环次数明确的情况,也适用于循环次数不明确的情况(满足条件继续循环,不满足就跳出)
格式:
sum(1-100): 5050
--------------------
sum(1-100): 偶数和2550
10.1.2 举例
-
求和,求偶数和
for ( int x = 0; x <= 100; x += 2){
Sum += x
}
结果:
int jc = 1; //定义最终结果变量
for ( int x = 1; x <= 5; x++ ){
Jc *= x
}
求偶数和还有一个办法:
Ge: 153 % 10 =3
Shi :153 / 10 % 10 = 5
Bai: 153 / 10 / 10 % 10 = 1
Qian:x/10/10/10%10
Wan :x/10/10/10/10%10
-
求5的阶乘
-
分析:什么是阶乘 n! = n * ( n -1 ) ( n - 2) … 3 2 * 1
while(判断条件语句){
循环语句;
控制条件语句;
}
-
在控制台输出所有的水仙花数
-
水仙花数就是指一个三位数,其各位数字的立方等于该数本身
-
Eg:153 = 1^3 + 5^3 + 3^3 = 1 + 125 +27 = 153
-
通过 for循环我们可以实现获取一个三位数,获取这个三位数的个十百位上的数据
-
获取方法:假设有一个数据为 153
while(true){
循环体
}
10.2 while 循环
10.2.1 定义
判断条件表达式的值为逻辑真时,重复执行循环体(不满足出去)
格式
for(;;){
循环体
}
10.2.2 死循环
do{
循环语句
} while(判断条件语句)
wc:for(int x = 0; x < 3; x++){ // wc:外层
nc:for(int y = 0; y < 4; y++){ nc:内层
if(y == 2){
break nc;
}
}
}
注意:一定设置结束条件,否则就会一直死循环。
10.2.3 While循环和for循环的区别?使用区别:
-
for 循环 控制条件定义的变量,只能在循环内使用。
-
while 循环 ….. 可以在循环外使用。
-
因为变量及早的从内存中消失,可以提高内存的使用效率。
另一种理解:
-
for 语句不仅适用于循环次数明确的情况,也适用于循环次数不明确的情况。
-
while 循环适用于循环次数不明确的情况。
先执行循环体,再判断继续条件不为逻辑真时,再执行循环体并判断条 件, 直到条件为假转去执行while下面的语句(不满足出去),所以至少要执行一次。
格式
10.3.2.1 break
break 的意思是中断
适用:switch、循环语句中(循环语句中加入了if判断的情况)
跳出单层循环(从最近的封闭循环体中跳出)
若想跳出多层循环 需要使用带标签的语句
-
格式:标签名:语句
10.3.2.2 continue
continue 的意思是跳出一次循环进入下一次的执行。
10.3.2.3 return
return关键字不是为了跳出循环体,更常用的功能是(结束一个方法),也就是退出一个方法。跳转到上层调用的方法。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)