<特别感谢对我学习提供帮助的相关书籍 和 网友,本文档仅是对本人该阶段学习的一个总结,多方借鉴了先人成果,如有不足还望赐教>
目录
一、Java名词解析
二、Java基本概念
1.标识符命名规范:
2.其他命名规范:
三、Java基本语法
1.基本数据类型
(1).内置数据类型
(2).引用置数据类型
2.变量类型及其声明
局部变量
实例变量
类变量(静态变量)
3.Java修饰符
访问控制修饰符
非访问修饰符
4.运算符
算数运算符
关系运算符
位运算符
逻辑运算符
赋值运算符
条件运算符
instanceof 运算符
Java运算符优先级
5.分支结构
if语句
if...else语句
switch语句
6.循环结构
while循环:
do ... ... while 循环:
for 循环:
for each 循环:
中断控制流程语句break&continue:
7.数组
声明数组变量
初始化数组
多维数组
不规则数组
数组的遍历
数组的拷贝
对象:对象是类的一个 实例 ,有 状态 和 行为 。
类:类是一个 模板 ,描述类对象的 行为 和 状态 。
方法:方法就是 行为 ,一个类中的相关动作都是在方法中完成的。
实例变量:每个对象都有独特的实例变量,对象的状态由这些实例变量的值决定
变量:通俗的理解变量就是用来在内存中存数的。当创建变量时,需要在内存中申请空间,内存管理系统根据变量的类型为变量分配存储空间(该空间只能用来存储该数据类型),变量命指向该空间。
Java两大数据类型:①内置数据类型 ②引用数据类型
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
八种基本类型: 六种数字类型(四种整数型 + 两种浮点型) + 一种字符类型 + 一种布尔类型
类型 | 大小 | 范围 | 初值 | 后缀 |
byte(字节型) | 1byte,8bit | -128 ~ 127 | 0 | |
short(短整型) | 2byte,16bit | -2^15 ~ 2^15-1 | 0 | |
int(整型) | 4byte,32bit | -2^31 ~ 2^31-1(-21多亿 ~ 21多亿) | 0 | |
long(长整型) | 8byte,64bit | -2^63 ~ 2^63-1 | 0L | L/l |
float(单精度浮点型) | 4byte,32bit | -3.403E38 ~ 3.403E38 | 0.0f | F/f |
double(双精度浮点型) | 8byte,64bit | -1.798E308 ~ - 4.9E324 | 0.0d | D/d |
boolean(布尔型) | 1byte,8bit | true/false(不能用0表示false) | false | |
char(字符型) | 2byte,16bit | ’\u0000‘~' ’\uffff '(16进制,0~65535) | /u0000(NULL) |
byte 和 short 类型用在大型数组中节约空间;long类型主要用在比较大整数的系统上,不过Java对于特大数值的处理提供了 BigInteger 与 BigDecimal 类;boolean类型只作为一种标记来记录true和false情况,注意在C++中非零值等价true,零等价false,这一点区别于Java。char类型 必须初始化 未初始化默认为空。
数据的 自动转换 与 强制转换
自动转换:在Java中 低级数据类型 可以向 高级数据类型 自动转换;(所谓低级和高级取决于数据类型所能表示的范围)
数据类型从低级到高级的排列为:byte > short > int > long > float > double(char > int)
因此 可以将 低级数据类型 直接赋值给 高级数据类型,同时 整型、实型(常量)、字符型 数据可以混合计算,在运算中,自动转换成同一类型,然后进行运算。
混合计算转换规则:当只有byte、short、int、char四种数据类型进行混合计算时,统一转换成int类型进行计算,所得到的结果为int类型。但是当包含long、float、double时则其余变量自动转换成多元操作中最高级的数据类型,运算结果亦为最高级的数据类型。
byte a = 1; short b = 1; int c = 1; char d = '1'; long e = 1; float f = 1.0f; double g = 1.0; /*低级数据类型 赋值 给高级数据类型*/ b = a;//short = byte c = a;//int = byte c = b;//int = short c = d;//int = char //注意char 和 byte、short 属于平行关系char同这两者之间不能进行直接赋值 /*混合数据类型计算*/ int h = a + b + d;//int = byte + short + char long i = a + b + c + d + e;//long = byte + short + int + char + long
强制转换:
强制类型转换规则:转换的数据类型必须是兼容的,并且目标类型取值范围要大于源数据类型变量的值(即高级数据类型可以强制转换成低级数据类型,但是高级数据类型的值必须在低级数据变量的范围内)
(type)value//type是要强制类型转换后的数据类型
警告:如果试图将一个数值从一种类型强制转换为另一种类型,而又超出了目标类型的表示范围,结果就会截断成一个完全不同的值。例如,(byte)300的实际值为44,byte的取值范围是-128~127。
C++注释:不要在boolean类型与任何数值类型之间进行强制类型转换,这样可以防止发生错误。只有极少数的情况下才需要将布尔类型转换为数值类型,这时可以使用条件表达式进行。
下面来看一个常见的问题:
short a = 1; a+=a;//true a = a+1;//false
为什么 a += a 正确 而 a = a + 1 错误呢?这是因为+=、-=、/=、*=、%=具备自动强制转换,会将运算结果自动转换成目标变量的数据类型。a += a 等价于 a = (data type of a)(a + 1)
//自增自减在某些情况下也具有自动强制转换的功能 short a = 1; short b = ++a;//++a 是int类型 请想转成short类型 byte c = 3; byte d = c++; b = ++c; b += a; c += b; c = ++b;//错误 自增自减不能讲高级 类型强转成低级类型 int s = 2; double e = s; float f = 1f; f = e++;//错误
注意:当用final修饰基本数据类型变量是将不会自动转换类型,转换的类型视等号左边的变量类型而定。
byte a1 = 0; final byte a2 = 3, a3 = 4; a1 = (a2 + a3);//求和运算后结果不是int类型,而是byte类型
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
在Java中,引用类型的变量类似C/C++指针。引用类型指向一个对象,指向对象的变量 是 引用变量。这些变量在声明时被指定为一个特定的类型。变量一旦声明不能改变。
三大类:①类 ②接口 ③数组 注释:Java语言本身不支持C++中的结构(struct)或联合(union)数据类型,它的复合数据类型一般都是通过类或接口进行构造,类提供了捆绑数据和方法的方式,同时可以针对程序外部进行信息隐藏。
在Java语言中,所有的变量在使用前必须声明。声明变量的基本格式如下:
type identifier [ = value][, identifier [= value] ...] ;
格式说明:type为Java数据类型。identifier是变量名。可以使用逗号隔开来声明多个同类型变量。
/*以下列出了一些变量的声明实例。注意有些包含了初始化过程*/
int a, b, c; // 声明三个int型整数:a、 b、c
int d = 3, e = 4, f = 5; // 声明三个整数并赋予初值
byte z = 22; // 声明并初始化 z
String s = "runoob"; // 声明并初始化字符串 s
double pi = 3.14159; // 声明了双精度浮点型变量 pi
char x = 'x'; // 声明变量 x 的值是字符 'x'。
Java语言支持的变量类型有:
public class Variable{
static int allClicks=0; // 类变量
String str="hello world"; // 实例变量
public void method(){
int i =0; // 局部变量
}
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/*在以下实例中age是一个局部变量。定义在pupAge()方法中,它的作用域就限制在这个方法中*/
package com.runoob.test;
public class Test{
public void pupAge(){
int age = 0;
age = age + 7;
System.out.println("小狗的年龄是: " + age);
}
public static void main(String[] args){
Test test = new Test();
test.pupAge();
}
}
/*
OutPut:
小狗的年龄是: 7
*/
/*在下面的例子中 age 变量没有初始化,所以在编译时会出错:*/
package com.runoob.test;
public class Test{
public void pupAge(){
int age;
age = age + 7;
System.out.println("小狗的年龄是 : " + age);
}
public static void main(String[] args){
Test test = new Test();
test.pupAge();
}
}
/*
OutPut:
Test.java:4:variable number might not have been initialized
age = age + 7;
^
1 error
*/
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
以下来几个例子理解:
public class DemoTest1 { public void OutPut() { if(flag) { System.out.println("实例变量可以定义在使用前可可以定义在使用后"); } } boolean flag = true; } public class DemoTest1 { boolean flag = true; public void OutPut() { if(flag) { System.out.println("实例变量可以定义在使用前可可以定义在使用后"); } } } public class Test { // static boolean flagStatic = true; // boolean flag = true; public static void main(String[] args) { //在静态方法中,调用实例变量需要创建对象 //但静态类变量可以直接调用 Test t = new Test(); if(t.flag) { System.out.println("实例变量可以定义在使用前可可以定义在使用后"); } if(flagStatic) { System.out.println("实例变量可以定义在使用前可可以定义在使用后"); } } static boolean flagStatic = true; boolean flag = true; }
import java.io.*;
public class Employee{
// 这个实例变量对子类可见
public String name;
// 私有变量,仅在该类可见
private double salary;
//在构造器中对name赋值
public Employee (String empName){
name = empName;
}
//设定salary的值
public void setSalary(double empSal){
salary = empSal;
}
// 打印信息
public void printEmp(){
System.out.println("名字 : " + name );
System.out.println("薪水 : " + salary);
}
public static void main(String[] args){
Employee empOne = new Employee("RUNOOB");
empOne.setSalary(1000);
empOne.printEmp();
}
}
/*
OutPut:
$ javac Employee.java
$ java Employee
名字 : RUNOOB
薪水 : 1000.0
*/
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
import java.io.*;
public class Employee {
//salary是静态的私有变量
private static double salary;
// DEPARTMENT是一个常量
public static final String DEPARTMENT = "开发人员";
public static String name;
static{
name = "XiaoMing";
}
public static void main(String[] args){
salary = 10000;
System.out.println(DEPARTMENT+"平均工资:"+salary);
}
}
/*
OutPut:
开发人员平均工资:10000.0
*/
Java主要修饰分类为:
修饰符用来定义类、方法 或 变量,通常放在语句的最前端。
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
修饰符 | 当前类 | 同包 | 派生类(同包) | 派生类(不同包) | 外部包 |
---|---|---|---|---|---|
public |
Y | Y | Y | Y | Y |
protected |
Y | Y | Y/N(继承了才能访问) | Y | N |
default |
Y | Y | Y | N | N |
private |
Y | N | N | N | N |
注释:以上访问修饰符访问等级从上到下依次降低
默认访问修饰符(不适用任何关键字)
使用默认访问修饰符声明的 变量 和 方法,对同一包中的类是可见的。接口里的变量都隐式声明为public static final,而接口里的方法默认情况下访问权限为 public。
/*如下所示,方法 和 类 的声明可以不适用任何修饰符*/
String version = "1.5.1";
boolean processOrder() {
return true;
}
私有访问修饰符 private
私有访问修饰符是最严格的访问级别,被声明为 private 的方法、变量 和 构造方法 只能被所属类访问,并且类和接口不能声明为 private。
声明为 private 的变量只能通过类中公共的方法被外部类访问。相比于直接访问公有属性,通过公有方法访问对象的私有属性,可以用来隐藏类的实现细节 和 保护数据。
public class Logger {
private String format;
public String getFormat() {
return this.format;
}
public void setFormat(String format) {
this.format = format;
}
}
公有访问修饰符 public
被声明为 public 类、方法、构造方法 和 接口 能有被任何其他类访问。
如果几个相互访问的public类分布在不同的包中,则需要导入相应public类所在的包。由于类的继承性,类所有的公有方法和变量都能被子类继承。
受保护的访问修饰符 protected
protected需要从以下两点来分析说明:
派生类能访问 protected 修饰符声明的方法和变量,这样就能保护不相关的类使用这些方法和变量。
/*下面的超类使用了 protected 访问修饰符,派生类重写了超类的 openSpeaker() 方法*/
class AudioPlayer {
protected boolean openSpeaker(Speaker sp) {
// 实现细节
}
}
class StreamingAudioPlayer extends AudioPlayer {
protected boolean openSpeaker(Speaker sp) {
// 实现细节
}
}
/*
如果把 openSpeaker() 方法声明为 private,那么除了 AudioPlayer 之外的类将不能访问该方法。
如果把 openSpeaker() 声明为 public,那么所有的类都能够访问该方法。
如果我们只想让该方法对其所在类的子类可见,则将该方法声明为 protected
*/
访问控制和继承的规则如下
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
static 修饰符,用来修饰类方法 和 类变量。
final修饰符,用来修饰类、方法 和 变量,final修饰的类不能被继承,修饰的方法不能被继承类重写,修饰的变量为常亮是不可修改的,在声明的同时必须初始化。
abstract修饰符,用来创建抽象类 和 抽象方法。
synchronixzed 和 volatile修饰符,主要用于线程的编程。
Static修饰符:
static关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝与类相对应。静态变量也称为类变量。局部变量不能被声明为static变量。
static关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据,然后计算这些数据。
/*mian()方法必须为公有静态方法,不会编译错误,但在运行时报错*/
public static void main(String[] args) {
System.out.println("Hello World");
}
/*OutPut:
Hello World
*/
public void main(String[] args) {
System.out.println("Hello World");
}
/*
OutPut:
错误: main 方法不是类 core.DemoTest 中的static, 请将 main 方法定义为:
public static void main(String[] args)
*/
static void main(String[] args) {
System.out.println("Hello World");
}
/*
OutPut:
错误: 在类 core.DemoTest 中找不到 main 方法, 请将 main 方法定义为:
public static void main(String[] args)
否则 JavaFX 应用程序类必须扩展javafx.application.Application
*/
final修饰符:
被final修饰的变量一次赋值终生不变。被final修饰的实例变量必须显示指定初始值。final修饰符通常和static修饰符一起来创建类常量。
类中的final方法可以被派生类继承,但是在派生类中不能被重写。
fianl类不能被继承任何特性。
abstract修饰符:
抽象类不能用来实例化对象,声明抽象类的唯一目的是为了将来对该类进行扩充。一个类不能同时被 abstract 和 final 修饰。如果一个类包含抽象方法,那么该类一定要声明为抽象类(反之不然),否则将出现变异错误,但抽象类也可以包含非抽象方法。
abstract class Caravan{
private double price;
private String model;
private String year;
public abstract void goFast(); //抽象方法(当前抽象类中不用写方法体,在子类中所有抽象方法将重写)
public void helloWorld(){//非抽象方法
System.out.println("Hello World");
}
}
抽象方法是一种没有任何实现的方法,该方法的具体实现由派生类提供。
抽象方法不能被声明为 final 和 static。
任何继承抽象类的派生类必须实现超类中所有的抽象方法,除非派生类也是抽象类。
如果一个类包含若干个抽象方法,那么该类必须声明为抽象类。抽象类可以不包含抽象方法。
抽象方法的声明以分号结尾,没有方法体(即上述提到的,方法体由子类提供)
synchronized修饰符:
synchronized 关键字声明的方法同一时间只能被一个线程访问。synchronized 修饰符可以应用于四个访问修饰符。
public synchronized void showDetails(){
.......
}
transient修饰符:
序列化的对象包含被 transient 修饰的实例变量时,java 虚拟机(JVM)跳过该特定的变量。该修饰符包含在定义变量的语句中,用来预处理类和变量的数据类型。
public transient int limit = 55; // 不会持久化
public int b; // 持久化
volatile 修饰符:
volatile 修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值。而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。一个volatile 对象引用可能是 null。
public class MyRunnable implements Runnable
{
private volatile boolean active;
public void run()
{
active = true;
while (active) // 第一行
{
// 代码
}
}
public void stop()
{
active = false; // 第二行
}
}
通常情况下,在一个线程调用 run() 方法(在 Runnable 开启的线程),在另一个线程调用 stop() 方法。 如果 第一行 中缓冲区的 active 值被使用,那么在 第二行 的 active 值为 false 时循环不会停止。但是以上代码中我们使用了 volatile 修饰 active,所以该循环会停止。
计算机的最基本用途之一就是执行数学运算,作为一门计算机语言,Java提供了一系列运算符来操作变量,主要可分为以下几类:
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
算数运算符用在数学表达式中,它们的作用和数学中的作用一样。下面表格罗列了所有算术运算符。
操作符 | 描述 | 操作数 |
+ | 加法 - 相加运算符两侧的值 | 双目 |
- | 减法 - 左操作数减去右操作数 | 双目 |
* | 乘法 - 相乘操作符两侧的值 | 双目 |
/ | 除法 - 左操作数除以右操作数 | 双目 |
% | 取余 - 左操作数除以右操作数的余数 | 双目 |
++ | 自增: 操作数的值增加1 | 单目 |
-- | 自减: 操作数的值减少1 | 单目 |
下面来详细的介绍++(自增)、--(自减) 和 + 运算符
前缀++(自增)、--(自减) :
运算符放在变量前边(前缀) 是先对变量执行自减自增运算 而后执行表达式运算。
后缀++(自增)、--(自减) :
运算符放在变量后边(后缀) 是先执行表达式运算 而后对变量执行自减自增运算。
注意:由于自增 和 自加 操作会改变变量的值,所以它们的操作数不能是 数值。例如 6++ 是不合法的语句。
public class DemoTest { public static void main(String[] args) { int a = 0; int b = 0; System.out.println("变量a执行后缀加加:" + a++); System.out.println("变量a现在的值是:" + a); System.out.println("变量b执行前缀加加:" + ++b); System.out.println("变量b现在的值是:" + b); } } /* OutPut: 变量a执行后缀加加:0 变量a现在的值是:1 变量b执行前缀加加:1 变量b现在的值是:1 */
不是说+运算符是算术运算符吗?执行的应该是算数运算才对,但上面代码System.out.println("变量a执行后缀加加:" + a++);中 + 号 明显是起到了连接 字符串 和 变量 的作用。看来 + 运算符 还有其他的功能。
字符串连接运算符 +
C++注释:与C++不同,Java没有提供运算符重载功能。程序员无法重定义 + 和 * 运算符,但是Java为字符串的连接 重载了 + 运算符 但没有重载其他的运算符,也没有给程序员在自己的类中重载运算符的机会。
连接符号 + 的 拼接规则:
- 当算数运算符前面有字符串连接时 则后面加号为连接符 拼接数字
- 当算数运算符前面没有字符串连接时,后面加号为算数运算符 计算数字
扩展:也可以采用静态方法拼接字符串 object.join("","",""); 第一个参数用为连接各个字符串的间隔符可以为空""
public class DemoTest { public static void main(String[] args) { int a = 1; int b = 1; String str = "和"; System.out.println(a + a + str + b + b); //添加括号则优先执行括号内的运算 括号内+的功能是算数运算符 System.out.println(a + a + str + (b + b)); //* / % 的运算优先级高于 + 执行时可以不添加括号 但任优先执行 再拼接 System.out.println(a + a + str + b/10); //System.out.println(a + a + str + b-10); 编译错误 /*静态方法join*/ System.out.println(String.join("/", "Li","Yi","Ping"," nizhenshuai")); } } /* OutPut: 2和11 2和2 2和0 Li/Yi/Ping/ nizhenshuai */
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
下面为Java支持的关系运算符
运算符 | 描述 | 例子(int A = 10, B = 20;) |
== | 检查两个操作数的值是否相等,如果相等则为真 | (A == B),false |
!= | 检查两个操作数的值是否不等,如果不等则为真 | (A != B),teue |
> | 检查左操作数的值是否大于右操作数的值,如果是则为真 | (A > B),false |
< | 检查左操作数的值是否小于右操作数的值,如果是则为真 | (A < B),true |
>= | 检查左操作数的值是否大于或等于右操作数的值,如果是则为真 | (A >= B),false |
<= | 检查左操作数的值是否小于或等于右操作数的值,如果是则为真 | (A <= B),true |
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
下表列出了位运算符的基本运算
操作符 | 描述 | 例子(int A = 60, B = 20;) |
---|---|---|
& | 如果相对应位都是1,则结果为1,否则为0 | (A&B),得到20,即0010 0100 |
| | 如果相对应位都是0,则结果为0,否则为1 | (A | B)得到60,即 0011 1100 |
^ | 如果相对应位值相同,则结果为0,否则为1 | (A ^ B)得到40,即0010 1000 |
〜 | 按位取反运算符翻转操作数的每一位,即0变成1,1变成0。 | (〜A)得到-61,即1100 0011 |
<< | 按位左移运算符。左操作数按位左移右操作数指定的位数。 | A << 2得到240,即 1111 0000 |
>> | 按位右移运算符。左操作数按位右移右操作数指定的位数。 | A >> 2得到15即 1111 |
>>> | 按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。 | A>>>2得到15即0000 1111 |
public class DemoTest {
public static void main(String[] args) {
int a = 60; /* 60 = 0011 1100 */
int b = 20; /* 20 = 0001 0100 */
int c = 0;
c = a & b; /* 20 = 0010 0100 */
System.out.println("a & b = " + c );
c = a | b; /* 60 = 0011 1100 */
System.out.println("a | b = " + c );
c = a ^ b; /* 40 = 0010 1000 */
System.out.println("a ^ b = " + c );
c = ~a; /*-61 = 1100 0011 */
System.out.println("~a = " + c );
c = ~b; /*-21 = 1110 1011 */
System.out.println("~b = " + 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 );
}
}
/*
OutPut:
a & b = 20
a | b = 60
a ^ b = 40
~a = -61
~b = -21
a << 2 = 240
a >> 2 = 15
a >>> 2 = 15
*/
扩展:数在内存中的存储形式
二进制在内存中的是以 补码 的形式存放的,并且 正数 和 负数 的 补码 不一样。
正数:补码 = 其本身; 反码 = 其本身
负数:补码 = 符号位不变,其余位求反,末尾加一; 反码 = 符号位为1 其余位求反 但末尾不加一
60 的原码为 0011 1100 补码为 0011 1100;现在对其进行 按位取反运算 得到1100 0011,并将其存储在计算机中(即补码形式),如果要将其输出首先需要你转换成十进制数(原码)。不难得出 原码 = 补码末尾减一,符号位不变,区域为求反。即,1100 0011减 1 为 1100 0010 ,再除符号位外按位取反 得原码 1011 1101 转换为十进制就是-61。
补码公式:-n = ~n + 1, ~n = -n -1 即~10为-11
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
下表列出了逻辑运算符的基本运算
操作符 | 描述 | 例子(boolean A = true, B = false) |
---|---|---|
& | 逻辑与运算符。当且仅当两个操作数都为真,条件才为真。 | (A && B)为假。 |
| | 逻辑或操作符。如果任何两个操作数任何一个为真,条件为真。 | A | | B)为真。 |
&& | 短路逻辑与运算符。当且仅当两个操作数都为真,条件才为真。 | (A && B)为假。 |
| | | 短路逻辑或操作符。如果任何两个操作数任何一个为真,条件为真。( | A | | B)为真。 |
! | 逻辑非运算符。用来反转操作数的逻辑状态。如果条件为true,则逻辑非运算符将得到false。 | !(A && B)为真。 |
短路逻辑运算 与 非短路逻辑运算 区别:
当使用短路与运算符时,两个操作数都为true时结果才为true,如果第一个操作数为false则结果必定为false,第二个操作数不再进行判断(运算符右边的代码块不执行),而与运算符不论何种情况运算符两边代码块都将执行,这就是短路运算符和非短路运算符的区别,短路运算有利于减少不必要的程序运行。
public class DemoTest { public static void main(String[] args) { int a = 10; int b = 20; if(a++ >= b && a >= b++) { }else { System.out.println("a的值发生改变了 ,为" + a); System.out.println("b的值没有发生改变,为" + b); } if(a++ >= b & a >= b++) { }else { System.out.println("a的值发生改变了 ,为" + a); System.out.println("b的值发生改变,为" + b); } } } /* OutPut: a的值发生改变了 ,为11 b的值没有发生改变,为20 a的值发生改变了 ,为12 b的值发生改变,为21 */
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
下面是Java语言支持的赋值运算符:
操作符 | 描述 | 例子 |
---|---|---|
= | 简单的赋值运算符,将右操作数的值赋给左侧操作数 | C = A + B将把A + B得到的值赋给C |
+ = | 加和赋值操作符,它把左操作数和右操作数相加赋值给左操作数 | C + = A等价于C = (data type)(C + A) |
- = | 减和赋值操作符,它把左操作数和右操作数相减赋值给左操作数 | C - = A等价于C = (data type)(C - A) |
* = | 乘和赋值操作符,它把左操作数和右操作数相乘赋值给左操作数 | C * = A等价于C = (data type)(C * A) |
/ = | 除和赋值操作符,它把左操作数和右操作数相除赋值给左操作数 | C / = A等价于C = (data type)(C / A) |
%= | 取模和赋值操作符,它把左操作数和右操作数取模后赋值给左操作数 | C%= A等价于C = (data type)(C%A) |
<< = | 左移位赋值运算符 | C << = 2等价于C = C << 2 |
>> = | 右移位赋值运算符 | C >> = 2等价于C = C >> 2 |
&= | 按位与赋值运算符 | C&= 2等价于C = C&2 |
^ = | 按位异或赋值操作符 | C ^ = 2等价于C = C ^ 2 |
| = | 按位或赋值操作符 | C | = 2等价于C = C | 2 |
注意:+=、-=、/=、*=、%= 都自带强转数据,关于强转见 基本数据类型
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
条件运算符亦称为三元(目)运算符
variable x = (boolean expression) ? value if true : value if false
variable x = (boolean expression) ? ((boolean expression) ? value if true : value if false) : value if false
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
该运算符用于操作对象实例,检查该对象是否是一个特定类型(类类型 或 接口类型)
( Object reference variable ) instanceof (class/interface type)
如果运算符左侧变量所指的对象是操作符右侧类或接口的一个对象,返回true
String name = "James";
boolean result = name instanceof String; // 由于 name 是 String 类型,所以返回真
如果被比较的对象兼容于右侧对象,该运算符仍然返回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);
}
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
下表中具有最高优先级的运算符在的表的最上面,最低优先级的在表的底部
类别 | 操作符 | 关联性 |
---|---|---|
后缀 | () [] . (点操作符) | 左到右 |
一元 | + + 、- -、!、〜 | 从右到左 |
乘性 | *、 /、% | 左到右 |
加性 | +、 - | 左到右 |
移位 | >> 、>>>、 << | 左到右 |
关系 | >、> = 、<、< = | 左到右 |
相等 | == 、 != | 左到右 |
按位与 | & | 左到右 |
按位异或 | ^ | 左到右 |
按位或 | | | 左到右 |
逻辑与 | && | 左到右 |
逻辑或 | | | | 左到右 |
条件 | ?: | 从右到左 |
赋值 | = 、+ = 、- = 、* = 、/ =、%=、 >> =、 << =、&= 、^ =、 | = | 从右到左 |
逗号 | , | 左到右 |
Java中有三种分支结构:
if(/*boolean expression*/){
/*...
code block
...*/
}
if(/*boolean expression*/){
/*...
code block
...*/
}else if(/*boolean expression*/){
/*...
code block
...*/
}else{
/*...
code block
...*/
}
switch (/*key*/) {
case /*value1*/:
/*code block*/
break;
case /*value2*/:
/*code block*/
break;
default:
/*code block*/
}
注意:switch语句中每个分支后面如果不加break跳出,将会自动执行余下的分支代码。
Java中有四种主要的循环结构:
注释:以上循环除了for each循环 都遵循 循环三要素: ①循环变量的初始化 ②循环条件(以循环变量为基础) ③循环变量的改变
whlie(/*boolean expression*/){
/*...
code block
...*/
}
do{
/*...
code block
...*/
}whlie(/*boolean expression*/);
for(/*init*/; /*boolean expression*/; /*update*/){
/*...
code block
...*/
}
关于for循环的几点说明:
/*for循环举例*/
for(int i = 0, j = 9; i < j; ++i, --j) {
System.out.print(i +" " + j);
}//优化内存 结构清晰
int i = 0, j = 0;//not int i = j = 0;
for(i = 1, j = 9; i < j; ++i, --j) {
System.out.print(i +" " + j);
}
for(i = 0, j = 9; i < j; System.out.print(i++ +" " + j--));
Java5 引入的一种主要用于数组的增强型 for 循环;for each 循环用来处理数组中的每个元素(其他类型的元素集合亦可,包括对一个集合中每个对象的循环遍历)而不必指定下标(index)。注意:对于 for 和 for each 的一些使用在数组中展开
for(/*declaration statement*/:/*expression*/) {
/*...
code block
...*/
}
break语句直接跳出当前循环,将控制转移到循环外部,不再执行当前循环。
Java中提供两种break语句:带标签 和 不带标签
带标签的break语句,用于跳出多重嵌套的循环语句,注意:标签必须放在希望跳出的最外层循环之前,并必须紧跟一个冒号。
/*label*/: while(/*boolean expression*/){ break /*label*/; }
不带标签的break语句,多用于switch语句 和 跳出单层循环,事实上两种循环可以应用到任何语句中,甚至可以应用到if语句或语句块中,但是注意,break语句只能跳出循环 而不能跳入循环。
while(/*boolean expression*/){ break; }
continue语句将控制转移到最内存循环的首部,即跳过本次循环直接进入下一次循环。
dataType[] arrayRefVar; //Java风格
dataType arrayRefVar[]; //C/C++风格
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
arrayRefVar = new dataType[arraySize];
上面的语句执行了两件事:
数组变量的声明和初始化可以用一条语句完成,如下所示:
dataType[] arrayRefVar = new dataType[arraySize];
dataType[] arrayRefVar = {value0, value1, ..., valuek};//Java中提供的一种创建数组对象并同时赋予初始值得简化形式
/*
注意:在使用这种语句时,不需要调用new,甚至还可以初始化一个匿名数组
new dataType[]{value0,value1,...,valuek}
这种表示方法将创建一个新的数组并利用括号中的值进行初始化,
数组的大小就是初始值得个数。使用这种语法形式可以在不创建新变量的情况下重新初始化一个数组。
例如:
arrayRefVar = new dataType[]{value0,value1,...,valuek};
*/
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
多维数组可以看成是数组的数组,比如二维数组就是一个特殊的一维数组,其每一个元素都是一个一维数组,例如:
String str[][] = new String[3][4];
多维数组的静态初始化
type[][] typeName = type[][]{{value0,value1},{value2,value3}};
多维数组的动态初始化(在初始化时指定数组长度)
type[][] typeName = new type[typeLength1][typeLength2];
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Java实际上没有多维数组,只有数组。多维数组被解释为“数组的数组”。例如上图所示,balances数组实际上是一个包含10个元素的数组,而每个数组又是由6个浮点数组成的数组。
表达式 balances[i] 引用第 i 个子数组,也就是二维表的第 i 行。它本身是一个数组,balances[i][j]引用这个数组的第 j 项。由上可知,Java中是单独地存取数组的某一行,所以可以让两行进行交换。
double[] temp = balances[i];
balances[i] = balances[i + 1];
balances[i + 1] = temp;
以上特性还能构造一个“不规则”数组,即数组的每行有不同的长度。以下为简单实例:
final int Max = 10;
int[][] odds = new int[Max][];
for(int i = 0; i < Max; ++i)
odds[i] = new int[i + 1];
for(int i = 0; i < odds.length; ++i) {
for(int j = 0; j < odds[i].length; ++j) {
odds[i][j] = j + 1;
System.out.print(odds[i][j] + " ");
}
System.out.println();
}
/*
OutPut:
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
1 2 3 4 5 6
1 2 3 4 5 6 7
1 2 3 4 5 6 7 8
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9 10
*/
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
for each循环语句 和 for循环语句 都不能自动处理二位数组的每一个元素。他是按照行,也就是一维数组处理的。想要访问二维数组的所有元素,需要使用两个嵌套的循环,如下所示:
for(int i = 0; i < odds.length; ++i) {
for(int j = 0; j < odds[i].length; ++j)
System.out.print(odds[i][j] + " ");
System.out.println();
}
for(int[] data0: odds) {
for(int data1: data0)
System.out.print(data1 + " ");
System.out.println();
}
/*
OutPut:
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
1 2 3 4 5 6
1 2 3 4 5 6 7
1 2 3 4 5 6 7 8
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9 10
*/
提示:想要快速地打印一个二维数组地数据元素列表,可以调用:System.out.println(Arrays.deepToString(odds));访问一维数组则可以调用System.out.println(Arrays.ToString(data0));
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
数组的拷贝可以分为 浅拷贝 和 深拷贝 。
浅拷贝只是将两个不同的数组名字指向同一块内存单元,并且没有将数据转移到新的内存单元。
int[] luckNumbers = smallPrimes;
luckNumbers[5] = 12;//now smallPrimes[5] is also 12
深拷贝即是再内存中重新分配空间,将数据拷贝到新内存空间中,并将数组名指向该空间。这里需要用到Arrays类的copyOf方法。
int[] copiedLuckyNumbers = Array.copyOf(luckNumbers, luckNumbers.length);
同时这个方法可以用来扩展数组的大小:
luckyNumbers = Array.copyOf(luckNumbers, 2*luckNumbers.length);
//这里数组多余元素初始化同数组一般初始化一样,比如数值类型的数组多余元素初始化为0。
//如果长度小于原始数组的长度,则只拷贝最前面的数据元素。
C++注释:ava数组与C++数组在堆栈上有很大不同,但基本上与分配在堆(heap)上的数组指针一样。也就是说: int[] a = new int[100];//Java 不同于 int a[100];//C++ 而等同于 int* a = new int[100];//C++ Java中的[ ]运算符被预定义为检查数组边界,而没有指针运算,即不能通过a加1得到数组的下一个元素。