【Java基础】--总结
文章目录
-
- 一、基础语法
- 标识符
- Java 修饰符
- Java 变量
- Java 数组
- Java枚举
-
- 范例
- Java 关键字
- Java注释
- Java 空行
- 继承
- 接口
- 二、Java 对象和类
-
- Java 中的对象
- Java中的类
- 构造方法
- 创建对象
- 访问对象的变量和方法
- 三、Java 基本数据类型
-
- 基本数据类型
- 基本类型值的范围
- 引用类型
- 四、Java 常量
- 五、Java 变量类型
-
- Java 局部变量
-
- 范例 1
- 范例 2
- 实例变量
-
- 范例 1
- 类变量 ( 静态变量 )
-
- 范例 1
- 六、Java 访问控制符
-
- 默认访问控制符 - 不使用任何关键字
- 私有访问控制符 - private
- 公有访问控制符 - public
- 受保护的访问控制符 - protected
- 访问控制和继承
- 七、Java 非访问修饰符
-
-
- static 修饰符
- final 修饰符
- abstract 修饰符
- synchronized 修饰符
- transient 修饰符
- volatile 修饰符
-
- 八、Java 运算符
-
- 算术运算符
-
- 自增自减运算符
-
- 范例
- 关系运算符
- 位运算符
- 逻辑运算符
-
- 短路逻辑运算符
- 赋值运算符
- 条件运算符 ( ?: )
-
- 范例
- instanceof 运算符
-
- 语法
- Java 运算符优先级
- 九、Java 条件判断
-
- 判断语句
- ? : 运算符(三元运算符)
- 范例
- 十、Java 条件之 if 语句
-
- 语法
-
- 注意
- 范例
- 十一、Java 条件之 if...else 语句
-
- 语法
- 范例
- 十二、Java 条件之 if...else if 语句
-
- 语法
- 范例
- 十三、Java 条件之 switch 语句
-
- 语法
- 范例
- Java break 语句
-
- 语法
- 范例
- Java continue 语句
-
- 语法
- 范例
一、基础语法
- 大小写敏感 :Java是大小写敏感的,这就意味着标识符Hello与hello是不同的。
- 类名 :对于所有的类来说,类名的首字母应该大写。如果类名由若干单词组成,那么每个单词的首字母应该大写,例如 MyFirstJavaClass
- 方法名 :所有的方法名都应该以小写字母开头。如果方法名含有若干单词,则后面的每个单词首字母大写。
- 源文件名 :源文件名必须和类名相同。当保存文件的时候,你应该使用类名作为文件名保存(切记Java是大小写敏感的),文件名的后缀为.java。(如果文件名和类名不相同则会导致编译错误)。
- 主方法入口 :所有的Java 程序由 public static void main(String []args) 方法开始执行
标识符
ava 所有的组成部分都需要名字。类名、变量名以及方法名都被称为标识符
关于 Java 标识符,有以下几点需要注意
- 所有的标识符都应该以字母(A-Z或者a-z),美元符($)、或者下划线(_)开始
- 首字符之后可以是字母(A-Z或者a-z),美元符($)、下划线(_)或数字的任何字符组合
- 关键字不能用作标识符
- 标识符是大小写敏感的
- 合法标识符举例:age、$salary、_value、__1_value
- 非法标识符举例:123abc、-salary
Java 修饰符
像其他语言一样,Java可以使用修饰符来修饰类中方法和属性。主要有两类修饰符:
- 访问控制修饰符 : default, public , protected, private
- 非访问控制修饰符 : final, abstract, strictfp
Java 变量
Java中主要有如下几种类型的变量
- 局部变量
- 类变量(静态变量)
- 成员变量(非静态变量)
Java 数组
数组是储存在堆上的对象,可以保存多个同类型变量
Java枚举
Java 5.0 引入了枚举,枚举限制变量只能是预先设定好的值
使用枚举可以减少代码中的 bug
例如,我们为果汁店设计一个程序,它将限制果汁为小杯、中杯、大杯。这就意味着它不允许顾客点除了这三种尺寸外的果汁
范例
class FreshJuice { enum FreshJuiceSize{ SMALL, MEDIUM , LARGE } FreshJuiceSize size;}public class FreshJuiceTest { public static void main(String []args){ FreshJuice juice = new FreshJuice(); juice.size = FreshJuice.FreshJuiceSize.MEDIUM ; }}
注意:
枚举可以单独声明或者声明在类里面 方法、变量、构造函数也可以在枚举中定义
Java 关键字
下面列出了 Java 保留字
这些保留字不能用于常量、变量、和任何标识符的名称
关键字 | 描述 |
---|---|
abstract | 抽象方法,抽象类的修饰符 |
assert | 断言条件是否满足 |
boolean | 布尔数据类型 |
break | 跳出循环或者label代码段 |
byte | 8-bit 有符号数据类型 |
case | switch语句的一个条件 |
catch | 和try搭配捕捉异常信息 |
char | 16-bit Unicode字符数据类型 |
class | 定义类 |
const | 未使用 |
continue | 不执行循环体剩余部分 |
default | switch语句中的默认分支 |
do | 循环语句,循环体至少会执行一次 |
double | 64-bit双精度浮点数 |
else | if条件不成立时执行的分支 |
enum | 枚举类型 |
extends | 表示一个类是另一个类的子类 |
final | 表示一个值在初始化之后就不能再改变了表示方法不能被重写,或者一个类不能有子类 |
finally | 为了完成执行的代码而设计的,主要是为了程序的健壮性和完整性,无论有没有异常发生都执行代码。 |
float | 32-bit单精度浮点数 |
for | for循环语句 |
goto | 未使用 |
if | 条件语句 |
implements | 表示一个类实现了接口 |
import | 导入类 |
instanceof | 测试一个对象是否是某个类的实例 |
int | 32位整型数 |
interface | 接口,一种抽象的类型,仅有方法和常量的定义 |
long | 64位整型数 |
native | 表示方法用非java代码实现 |
new | 分配新的类实例 |
package | 一系列相关类组成一个包 |
private | 表示私有字段,或者方法等,只能从类内部访问 |
protected | 表示字段只能通过类或者其子类访问子类或者在同一个包内的其他类 |
public | 表示共有属性或者方法 |
return | 方法返回值 |
short | 16位数字 |
static | 表示在类级别定义,所有实例共享的 |
strictfp | 浮点数比较使用严格的规则 |
super | 表示基类 |
switch | 选择语句 |
synchronized | 表示同一时间只能由一个线程访问的代码块 |
this | 表示调用当前实例或者调用另一个构造函数 |
throw | 抛出异常 |
throws | 定义方法可能抛出的异常 |
transient | 修饰不要序列化的字段 |
try | 表示代码块要做异常处理或者和finally配合表示是否抛出异常都执行finally中的代码 |
void | 标记方法不返回任何值 |
volatile | 标记字段可能会被多个线程同时访问,而不做同步 |
while | while循环 |
Java注释
类似于C/C++,Java也支持单行以及多行注释。注释中的字符将被Java编译器忽略。
public class HelloWorld { /* 这是第一个Java程序 * 它将打印 Hello World */ public static void main(String []args){System.out.println("Hello World"); }}
Java 空行
空白行,或者有注释的行,Java 编译器都会忽略掉(注释行中如果使用了unicode之类的编码解码字符有可能编译器会识别。)
继承
Java 中,一个类可以由其他类派生
如果要创建一个类,而且已经存在一个类具有你所需要的属性或方法,那么你可以将新创建的类继承该类
利用继承的方法,可以重用已存在类的方法和属性,而不用重写这些代码
被继承的类称为超类(super class),派生类称为子类 ( subclass )
接口
Java 中,接口可理解为对象间相互通信的协议。接口在继承中扮演着很重要的角色
接口只定义派生要用到的方法,但是方法的具体实现完全取决于派生类
二、Java 对象和类
Java 从设计之初就已经是一门面向对象的语言
如果你以前没有接触过面向对象的编程语言,那可能需要先了解一些面向对象语言的一些基本特征,在头脑里头形成一个基本的面向对象的概念,这样有助于你更容易的学习 Java 的面向对象编程
Java作为一种面向对象语言,支持以下基本概念
- 封装
- 多态
- 继承
- 抽象类
- 类
- 对象
- 实例
- 方法
- 重载
类和对象的概念
术语 | 说明 |
---|---|
对象 | 对象是类的一个实例,有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等 |
类 | 类是一个模板,它描述一类对象的行为和状态 |
Java 中的对象
在软件开发中,方法操作对象内部状态的改变,对象的相互调用也是通过方法来完成
Java中的类
类可以看成是创建 Java 对象的模板
我们通过一个类 Dog 来解释 Java 中的类
public class Dog{ String breed; int age; String color; void barking(){ System.out.println("barking..."); } void hungry(){ System.out.println("hungry..."); } void sleeping(){ System.out.println("sleeping..."); }}
一个类可以包含以下类型变量
-
局部变量 :在方法、构造方法或者语句块中定义的变量被称为局部变量
变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁
-
成员变量 :成员变量是定义在类中,方法体之外的变量
这种变量在创建对象的时候实例化
成员变量可以被类中方法、构造方法和特定类的语句块访问
-
类变量 :类变量也声明在类中,方法体之外,但必须声明为 static 类型
一个类可以拥有多个方法,比如上面的代码中的:barking()、hungry() 和 sleeping()都是 Dog 类的方法
构造方法
每个类都有构造方法
如果没有显式地为类定义构造方法,Java 编译器将会为该类提供一个默认构造方法
在创建一个对象的时候,至少要调用一个构造方法
构造方法的名称必须与类同名,一个类可以有多个构造方法
下面的代码为类 Puppy 定义了两个构造方法
public class Puppy { public Puppy(){ //这是一个无参构造方法 如果手动声明了这个 则需要对有参的构造方法进行手动声明 默认无参构造 } public Puppy(String name){ // 这个构造器仅有一个参数:name }}
创建对象
对象是根据类创建的
Java 使用关键字 new 来创建一个新的对象
创建对象需要以下三步
- 声明 :声明一个对象,包括对象名称和对象类型
- 实例化 :使用关键字new来创建一个对象
- 初始化 :使用new创建对象时,会调用构造方法初始化对象
下面的代码创建了一个 Puppy 类的对象
public class Puppy{ public Puppy(String name) { //这个构造器仅有一个参数:name System.out.println("小狗的名字是 : " + name ); } public static void main(String []args) { // 下面的语句将创建一个Puppy对象 Puppy myPuppy = new Puppy( "tom" ); }}
编译运行以上 Java 代码,输出结果如下
小狗的名字是 : tom
访问对象的变量和方法
我们可以通过已创建的对象来访问成员变量和成员方法
/* 实例化对象 */ObjectReference = new Constructor();/* 访问类中的变量 */ObjectReference.variableName;/* 访问类中的方法 */ObjectReference.MethodName();
下面的范例访问了对象 myPuppy 的 setAge() 和 getAge() 方法
public class Puppy{ int puppyAge; public Puppy(String name){ // 这个构造器仅有一个参数:name System.out.println("小狗的名字是 : " + name ); } public void setAge( int age ){puppyAge = age; } public int getAge( ){System.out.println("小狗的年龄为 : " + puppyAge ); return puppyAge; } public static void main(String []args){ /* 创建对象 */ Puppy myPuppy = new Puppy( "tom" ); /* 通过方法来设定age */ myPuppy.setAge( 2 ); /* 调用另一个方法获取age */ myPuppy.getAge( ); /*你也可以像下面这样访问成员变量 */ System.out.println("变量值 : " + myPuppy.puppyAge ); }}
编译运行以上 Java 代码,输出结果如下
小狗的名字是 : tom小狗的年龄为 : 2变量值 : 2
三、Java 基本数据类型
Java 语言中的数据类型可以分为以下两大类
- 基本数据类型
- 引用数据类型
基本数据类型
byte
short
int
long
float
double
boolean
char
Java 语言提供了八种基本类型:六种数字类型 ( 四个整数型,两个浮点型 ),一种字符类型,一种布尔型
-
byte:
- byte 数据类型是 8 位、有符号的,以二进制补码表示的整数
- 最小值是 -128 ( -2^7 )
- 最大值是 127 ( 2^7-1 )
- 默认值是 0
- byte 类型用在大型数组中节约空间,主要代替整数,因为 byte 变量占用的空间只有 int 类型的四分之一
例如
byte a = 100;byte b = -50;
-
short:
- short 数据类型是 16 位、有符号的以二进制补码表示的整数
- 最小值是 -32768 ( -2^15 )
- 最大值是 32767 ( 2^15 - 1 )
- short 数据类型也可以像 byte 那样节省空间,一个 short 变量是 int 型变量所占空间的二分之一
- 默认值是 0
例如
short s = 1000;short r = -20000;
-
int
- int 数据类型是 32 位、有符号的以二进制补码表示的整数
- 最小值是 -2,147,483,648 ( -2^31 )
- 最大值是 2,147,483,647 ( 2^31 - 1 )
- 一般地整型变量默认为 int 类型
- 默认值是 0
例如
int a = 100000;int b = -200000;
-
long
- long 数据类型是 64 位、有符号的以二进制补码表示的整数
- 最小值是 -9,223,372,036,854,775,808 ( -2^63 )
- 最大值是 9,223,372,036,854,775,807 ( 2^63 -1 )
- long 类型主要使用在需要比较大整数的系统上
- 默认值是 0L
例如
long a = 100000L;Long b = -200000L;
“L” 理论上不分大小写,但是若写成"l"容易与数字"1"混淆,不容易分辩,所以最好大写
-
float
- float 数据类型是单精度、32 位、符合 IEEE 754 标准的浮点数
- float 在储存大型浮点数组的时候可节省内存空间
- 默认值是 0.0f
- 浮点数不能用来表示精确的值,如货币
例如
float f1 = 234.5f;
-
double
- double 数据类型是双精度、64 位、符合 IEEE 754 标准的浮点数
- 浮点数的默认类型为 double 类型
- double 类型同样不能表示精确的值,如货币
- 默认值是 0.0d
例如
double d1 = 123.4;
-
boolean
- boolean 数据类型表示一位的信息
- 只有两个取值:true 和 false
- 这种类型只作为一种标志来记录 true/false 情况
- 默认值是 false
例如
boolean one = true;
-
char
- char 类型是一个单一的 16 位 Unicode 字符
- 最小值是 \u0000 ( 即为0 )
- 最大值是 \uffff ( 即为 65,535 )
- char 数据类型可以储存任何字符
例如
char letter = 'A';
JAVA 中还存在另外一种基本类型 void,它也有对应的包装类 java.lang.Void,不过我们无法直接对它们进行操作
基本类型值的范围
各种基本类型值的范围,我们无需去记住,Java 已经把它们的值的范围用常量的方式定义在对应的包装类中了
public class PrimitiveTypeTest { public static void main(String[] args) { // byte System.out.println("基本类型:byte 二进制位数:" + Byte.SIZE); System.out.println("包装类:java.lang.Byte"); System.out.println("最小值:Byte.MIN_VALUE=" + Byte.MIN_VALUE); System.out.println("最大值:Byte.MAX_VALUE=" + Byte.MAX_VALUE); System.out.println(); // short System.out.println("基本类型:short 二进制位数:" + Short.SIZE); System.out.println("包装类:java.lang.Short"); System.out.println("最小值:Short.MIN_VALUE=" + Short.MIN_VALUE); System.out.println("最大值:Short.MAX_VALUE=" + Short.MAX_VALUE); System.out.println(); // int System.out.println("基本类型:int 二进制位数:" + Integer.SIZE); System.out.println("包装类:java.lang.Integer"); System.out.println("最小值:Integer.MIN_VALUE=" + Integer.MIN_VALUE); System.out.println("最大值:Integer.MAX_VALUE=" + Integer.MAX_VALUE); System.out.println(); // long System.out.println("基本类型:long 二进制位数:" + Long.SIZE); System.out.println("包装类:java.lang.Long"); System.out.println("最小值:Long.MIN_VALUE=" + Long.MIN_VALUE); System.out.println("最大值:Long.MAX_VALUE=" + Long.MAX_VALUE); System.out.println(); // float System.out.println("基本类型:float 二进制位数:" + Float.SIZE); System.out.println("包装类:java.lang.Float"); System.out.println("最小值:Float.MIN_VALUE=" + Float.MIN_VALUE); System.out.println("最大值:Float.MAX_VALUE=" + Float.MAX_VALUE); System.out.println(); // double System.out.println("基本类型:double 二进制位数:" + Double.SIZE); System.out.println("包装类:java.lang.Double"); System.out.println("最小值:Double.MIN_VALUE=" + Double.MIN_VALUE); System.out.println("最大值:Double.MAX_VALUE=" + Double.MAX_VALUE); System.out.println(); // char System.out.println("基本类型:char 二进制位数:" + Character.SIZE); System.out.println("包装类:java.lang.Character"); // 以数值形式而不是字符形式将Character.MIN_VALUE输出到控制台 System.out.println("最小值:Character.MIN_VALUE=" + (int) Character.MIN_VALUE); // 以数值形式而不是字符形式将Character.MAX_VALUE输出到控制台 System.out.println("最大值:Character.MAX_VALUE=" + (int) Character.MAX_VALUE); } }
编译运行以上 Java 代码,输出结果如下
基本类型:byte 二进制位数:8包装类:java.lang.Byte最小值:Byte.MIN_VALUE=-128最大值:Byte.MAX_VALUE=127基本类型:short 二进制位数:16包装类:java.lang.Short最小值:Short.MIN_VALUE=-32768最大值:Short.MAX_VALUE=32767基本类型:int 二进制位数:32包装类:java.lang.Integer最小值:Integer.MIN_VALUE=-2147483648最大值:Integer.MAX_VALUE=2147483647基本类型:long 二进制位数:64包装类:java.lang.Long最小值:Long.MIN_VALUE=-9223372036854775808最大值:Long.MAX_VALUE=9223372036854775807基本类型:float 二进制位数:32包装类:java.lang.Float最小值:Float.MIN_VALUE=1.4E-45最大值:Float.MAX_VALUE=3.4028235E38基本类型:double 二进制位数:64包装类:java.lang.Double最小值:Double.MIN_VALUE=4.9E-324最大值:Double.MAX_VALUE=1.7976931348623157E308基本类型:char 二进制位数:16包装类:java.lang.Character最小值:Character.MIN_VALUE=0最大值:Character.MAX_VALUE=65535
Float 和 Double 的最小值和最大值都是以科学记数法的形式输出的,结尾的 "E+数字"表示 E 之前的数字要乘以 10 的多少次方
比如 3.14E3 就是 3.14 × 103=3140,3.14E-3 就是 3.14 x 10-3=0.00314
引用类型
1.Java 中,引用类型指向一个对象,指向对象的变量是引用变量
这些变量在声明时被指定为一个特定的类型,比如 Employee、Puppy 等变量一旦声明后,类型就不能被改变了
- 对象、数组都是引用数据类型
- 所有引用类型的默认值都是 null
- 一个引用变量可以用来引用与任何与之兼容的类型
例如
Site site = new Site("Twle");
四、Java 常量
常量在程序运行时,不会被修改的量
Java 中使用 final 关键字来修饰常量,声明方式和变量类似
final double PI = 3.1415927;
虽然常量名也可以用小写,但为了便于识别,通常使用大写字母表示常量
字面量可以赋给任何内置类型的变量
byte a = 68;char a = 'A'
byte、int、long、和 short 都可以用十进制、16 进制以及 8 进制的方式来表示
当使用常量的时候,前缀 0 表示 8 进制,而前缀 0x 代表 16 进制
int decimal = 100;int octal = 0144;int hexa = 0x64;
Java 的字符串常量也是包含在两个引号之间的字符序列
下面是一些字符串型字面量的示例
"Hello World""two\nlines""\"This is in quotes\""
字符串常量和字符常量都可以包含任何 Unicode 字符
char a = '\u0001';String a = "\u0001";
Java 语言支持一些特殊的转义字符序列
符号 | 字符含义 |
---|---|
\n | 换行 (0x0a) |
\r | 回车 (0x0d) |
\f | 换页符(0x0c) |
\b | 退格 (0x08) |
\0 | 空字符 (0x20) |
\s | 字符串 |
\t | 制表符 |
" | 双引号 |
’ | 单引号 |
\ | 反斜杠 |
\ddd | 八进制字符 (ddd) |
\uxxxx | 16进制Unicode字符 (xxxx) |
五、Java 变量类型
Java 语言中,所有的变量在使用前必须声明
声明变量的基本语法如下
type identifier [ = value][, identifier [= value] ...] ;
其中
- type 为 Java 数据类型
- identifier 是变量名
- 可以使用逗号隔开来声明多个同类型变量
下面的代码是一些变量的声明,它们同时还包含了初始化过程
int a, b, c; // 声明三个int型整数:a、 b、cint d = 3, e = 4, f = 5; // 声明三个整数并赋予初值byte z = 22; // 声明并初始化 zString s = "twle";// 声明并初始化字符串 sdouble pi = 3.14159; // 声明了双精度浮点型变量 pichar x = 'x'; // 声明变量 x 的值是字符 'x'。
Java语言支持的变量类型有
- 类变量:独立于方法之外的变量,用 static 修饰
- 实例变量:独立于方法之外的变量,不过没有 static 修饰
- 局部变量:类的方法中的变量
public class Variable{ static int allClicks=0; // 类变量 String str="hello world"; // 实例变量 public void method(){ int i =0; // 局部变量 }}
Java 局部变量
- 局部变量声明在方法、构造方法或者语句块中
- 局部变量在方法、构造方法、或者语句块被执行的时候创建,当它们执行完成后,变量将会被销毁
- 访问修饰符不能用于局部变量
- 局部变量只在声明它的方法、构造方法或者语句块中可见
- 局部变量是在栈上分配的
- 局部变量没有默认值,所以局部变量被声明后,必须经过初始化,才可以使用
范例 1
下面的范例中, age是一个局部变量,它定义在 pupAge() 方法中,它的作用域就限制在这个方法中
package com.twle.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(); }}
编译运行以上 Java 代码,输出结果如下
小狗的年龄是: 7
范例 2
下面的范例中,age 变量没有初始化,所以在编译时会出错
package com.twle.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(); }}
编译运行以上 Java 代码,输出结果如下
Test.java:4:variable number might not have been initializedage = age + 7; ^1 error
实例变量
- 实例变量声明在一个类中,但在方法、构造方法和语句块之外
- 当一个对象被实例化之后,每个实例变量的值就跟着确定
- 实例变量在对象创建的时候创建,在对象被销毁的时候销毁
- 实例变量的值应该至少被一个方法、构造方法或者语句块引用, 使得外部能够通过这些方式获取实例变量信息
- 实例变量可以声明在使用前或者使用后
- 访问修饰符可以修饰实例变量
- 实例变量对于类中的方法、构造方法或者语句块是可见的。一般情况下应该把实例变量设为私有。通过使用访问修饰符可以使实例变量对子类可见
- 实例变量具有默认值。数值型变量的默认值是 0,布尔型变量的默认值是 false,引用类型变量的默认值是 null。变量的值可以在声明时指定,也可以在构造方法中指定
- 实例变量可以直接通过变量名访问。但在静态方法以及其他类中,就应该使用完全限定名:ObejectReference.VariableName
范例 1
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(); }}
编译运行以上 Java 代码,输出结果如下
$ javac Employee.java $ java Employee名字 : RUNOOB薪水 : 1000.0
类变量 ( 静态变量 )
- 类变量也称为静态变量,在类中以 static 关键字声明,但必须在方法构造方法和语句块之外
- 无论一个类创建了多少个对象,类只拥有类变量的一份拷贝
- 静态变量除了被声明为常量外很少使用。常量是指声明为 public/private,final和static类型的变量。常量初始化后不可改变
- 静态变量储存在静态存储区。经常被声明为常量,很少单独使用 static 声明变量
- 静态变量在程序开始时创建,在程序结束时销毁
- 与实例变量具有相似的可见性。但为了对类的使用者可见,大多数静态变量声明为 public 类型
- 默认值和实例变量相似。数值型变量默认值是0,布尔型默认值是false,引用类型默认值是null。变量的值可以在声明的时候指定,也可以在构造方法中指定。此外,静态变量还可以在静态语句块中初始化
- 静态变量可以通过: ClassName.VariableName 的方式访问
- 类变量被声明为
public static final
类型时,类变量名称一般建议使用大写字母。如果静态变量不是 public 和 final 类型,其命名方式与实例变量以及局部变量的命名方式一致
范例 1
import java.io.*;public class Employee { //salary是静态的私有变量 private static double salary; // DEPARTMENT是一个常量 public static final String DEPARTMENT = "开发人员"; public static void main(String args[]){ salary = 10000; System.out.println(DEPARTMENT+"平均工资:"+salary); }}
编译运行以上 Java 代码,输出结果如下
开发人员平均工资:10000.0
如果其它类想要访问该变量,可以这样访问: Employee.DEPARTMENT
六、Java 访问控制符
Java 中可以使用 访问控制符 来保护对类、变量、方法和构造方法的访问
Java 语言中有 4 种不同的访问权限
-
default ( 即缺省,什么也不写 )
在同一包内可见,不使用任何控制符
使用对象:类、接口、变量、方法
-
private
在同一类内可见
使用对象:变量、方法
注意:不能修饰类 ( 外部类 )
-
public
对所有类可见
使用对象:类、接口、变量、方法
-
protected
对同一包内的类和所有子类可见
使用对象:变量、方法
注意:不能修饰类 ( 外部类 )
下表列出了这些权限的对比
访问控制符 | 当前类 | 同一包内 | 子孙类 | 其它包 |
---|---|---|---|---|
public | Y | Y | Y | Y |
protected | Y | Y | Y | N |
default | Y | Y | N | N |
private | Y | N | N | N |
默认访问控制符 - 不使用任何关键字
默认访问控制符声明的变量和方法,对同一个包内的类是可见的
接口的变量都隐式声明为 public static final
接口的方法默认情况下访问权限为 public
变量和方法的声明可以不使用任何控制符
String version = "1.5.1";boolean processOrder() { return true;}
私有访问控制符 - private
私有访问控制符是最严格的访问级别,声明为 private 的方法、变量和构造方法只能被所属类内部访问
类和接口不能声明为 private
private 声明的变量只能通过类中公共的 getter 方法被外部类访问
private 访问控制符的使用主要用来隐藏类的实现细节和保护类的数据
下面的类使用了私有访问控制符修饰 format 变量
public class Logger { private String format; public String getFormat() { return this.format; } public void setFormat(String format) { this.format = format; }}
上面的代码中,Logger 类中的 format 变量为私有变量,所以其它类不能直接得到和设置该变量的值
为了使其它类能够操作该变量,还定义了两个 public 方法:getFormat() ( 返回 format 的值 ) 和 setFormat(String) ( 设置 format 的值 )
公有访问控制符 - public
public 访问控制符修饰的类、方法、构造方法和接口能够被任何其它类访问
如果几个相互访问的 public 类分布在不同的包中,则需要导入相应 public 类所在的包
由于类的继承性,类所有的公有方法和变量都能被其子类继承
以下函数使用了公有访问控制
public static void main(String[] arguments) { // ...}
Java 程序的 main() 方法必须设置成公有的,否则,Java 解释器将不能运行该类
受保护的访问控制符 - protected
protected 访问控制符修饰的变量、方法和构造器能被同一个包中的任何其它类访问,也能够被不同包中的子类访问
- protected 访问控制符不能修饰类和接口
- 方法和成员变量能够声明为 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
访问控制和继承
Java 中的访问控制和继续有以下规则
- 父类中声明为 public 的方法在子类中也必须为 public
- 父类中声明为 protected 的方法在子类中要么声明为 protected,要么声明为 public,不能声明为 private
- 父类中声明为 private 的方法,不能够被继承
七、Java 非访问修饰符
除了前一章节中提到的 4 种访问控制符外,Java 还提供了许多非访问修饰符
-
static 修饰符,用来修饰类方法和类变量
-
final 修饰符,用来修饰类、方法和变量
final 修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的
-
abstract 修饰符,用来创建抽象类和抽象方法
-
synchronized 和 volatile 修饰符,主要用于多线程的编程
static 修饰符
-
静态变量
static 关键字用于声明独立于对象的静态变量
无论一个类实例化多少对象,它的静态变量只有一份拷贝
静态变量也被称为类变量
局部变量不能被声明为 static 变量
-
静态方法:
static 关键字可以用于声明独立于对象的静态方法
静态方法不能使用类的非静态变量
静态方法从参数列表得到数据,然后计算这些数据
类的静态变量和静态方法可以直接使用 classname.variablename 和 classname.methodname 的方式访问
public class InstanceCounter { private static int numInstances = 0; protected static int getCount() { return numInstances; } private static void addInstance() { numInstances++; } InstanceCounter() { InstanceCounter.addInstance(); } public static void main(String[] arguments) { System.out.println("Starting with " + InstanceCounter.getCount() + " instances"); for (int i = 0; i < 500; ++i){ new InstanceCounter(); } System.out.println("Created " + InstanceCounter.getCount() + " instances"); }}
编译运行以上 Java 代码,输出结果如下
Started with 0 instancesCreated 500 instances
final 修饰符
-
final 变量
final 变量能被显式地初始化并且只能初始化一次
被声明为 final 的对象的引用不能指向不同的对象
但是 final 对象里的数据可以被改变
也就是说 final 对象的引用不能改变,但是里面的值可以改变
final 修饰符通常和 static 修饰符一起使用来创建类常量
public class Test{ final int value = 10; // 下面是声明常量的实例 public static final int BOXWIDTH = 6; static final String TITLE = "Manager"; public void changeValue(){ value = 12; //将输出一个错误 }}
-
final 方法
类中的 final 方法可以被子类继承,但是不能被子类修改
声明 final 方法的主要目的是防止该方法的内容被修改
public class Test{ public final void changeName(){// 方法体 }}
-
final 类
final 类不能被继承,没有类能够继承 final 类的任何特性
public final class Test { // 类体}
abstract 修饰符
-
抽象类:
抽象类不能用来实例化对象,声明抽象类的唯一目的是为了将来对该类进行扩充
一个类不能同时被 abstract 和 final 修饰
如果一个类包含抽象方法,那么该类一定要声明为抽象类,否则将出现编译错误
抽象类可以包含抽象方法和非抽象方法
abstract class Caravan{ private double price; private String model; private String year; public abstract void goFast(); //抽象方法 public abstract void changeColor();}
-
抽象方法
抽象方法是一种没有任何实现的方法,该方法的的具体实现由子类提供
抽象方法不能被声明成 final 和 static
任何继承抽象类的子类必须实现父类的所有抽象方法,除非该子类也是抽象类
如果一个类包含若干个抽象方法,那么该类必须声明为抽象类
抽象类可以不包含抽象方法
抽象方法的声明以分号结尾,如如: public abstract sample();
public abstract class SuperClass{ abstract void m(); //抽象方法}class SubClass extends SuperClass{ //实现抽象方法 void m(){ ......... }}
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 运算符
运算符是一种告诉编译器执行特定的数学或逻辑操作的符号
Java 语言内置了丰富的运算符
Java 支持以下几类运算符
- 算术运算符
- 关系运算符
- 位运算符
- 逻辑运算符
- 赋值运算符
- 其他运算符
算术运算符
算术运算符用在数学表达式中,它们的作用和在数学中的作用一样
下表下表列出了 Java 语言中所有的算术运算符
我们假定整数变量 A 的值为 10,变量 B 的值为20
操作符 | 描述 | 示例 |
---|---|---|
+ | 加法 - 相加运算符两侧的值 | A + B 等于 30 |
- | 减法 - 左操作数减去右操作数 | A – B 等于 -10 |
* | 乘法 - 相乘操作符两侧的值 | A * B 等于 200 |
/ | 除法 - 左操作数除以右操作数 | B / A 等于 2 |
% | 取模 - 左操作数除以右操作数的余数 | B%A 等于 0 |
++ | 自增: 操作数的值增加1 | B++ 或 ++B 等于 21 |
– | 自减: 操作数的值减少1 | B-- 或 --B 等于 19 |
下面的代码简单的演示了这些运算符的使用
public class MathOperator { public static void main(String[] args) { int a = 10; int b = 20; int c = 25; int d = 25; System.out.println("a + b = " + (a + b) ); System.out.println("a - b = " + (a - b) ); System.out.println("a * b = " + (a * b) ); System.out.println("b / a = " + (b / a) ); System.out.println("b % a = " + (b % a) ); System.out.println("c % a = " + (c % a) ); System.out.println("a++ = " + (a++) ); System.out.println("a-- = " + (a--) ); // 查看 d++ 与 ++d 的不同 System.out.println("d++ = " + (d++) ); System.out.println("++d = " + (++d) ); }}
运行范例 »
编译运行以上 Java 代码,输出结果如下
a + b = 30a - b = -10a * b = 200b / a = 2b % a = 0c % a = 5a++ = 10a-- = 11d++ = 25++d = 27
自增自减运算符
自增 ( ++ ) 自减 ( – ) 运算符
这两个运算符是一种特殊的算术运算符,在算术运算符中需要两个操作数来进行运算,而自增自减运算符是一个操作数
public class selfAddMinus{ public static void main(String[] args){ int a = 3;//定义一个变量; int b = ++a;//自增运算 int c = 3; int d = --c;//自减运算 System.out.println("进行自增运算后的值等于"+b); System.out.println("进行自减运算后的值等于"+d); }}
编译运行以上 Java 代码,输出结果如下
进行自增运算后的值等于4进行自减运算后的值等于2
在这个范例中
int b = ++a;
拆分运算过程为: a=a+1=4; b=a=4, 最后结果为b=4,a=4int d = --c;
拆分运算过程为: c=c-1=2; d=c=2, 最后结果为d=2,c=2- 缀自增自减法 (++a,–a)😗* 先进行自增或者自减运算,再进行表达式运算
- 后缀自增自减法 (a++,a–)😗* 先进行表达式运算,再进行自增或者自减运算
范例
public class selfAddMinus{ public static void main(String[] args){ int a = 5;//定义一个变量; int b = 5; int x = 2*++a; int y = 2*b++; System.out.println("自增运算符前缀运算后a="+a+",x="+x); System.out.println("自增运算符后缀运算后b="+b+",y="+y); }}
编译运行以上 Java 代码,输出结果如下
自增运算符前缀运算后 a=6,x=12自增运算符后缀运算后 b=6,y=10
关系运算符
下表列出了 Java 支持的关系元素符
我们假定整数变量 A 的值为 10,变量 B 的值为 20
运算符 | 描述 | 示例 |
---|---|---|
== | 检查两个操作数的值是否相等,相等则条件为真 | ( A == B) 为假 (非真) |
!= | 检查两个操作数的值是否相等,值不相等则条件为真 | ( A != B) 为真 |
> | 检查左操作数的值是否大于右操作数的值,如果是那么条件为真 | ( A > B ) 非真 |
< | 检查左操作数的值是否小于右操作数的值,如果是那么条件为真 | ( A < B ) 为真 |
>= | 检查左操作数的值是否大于或等于右操作数的值,如果是那么条件为真 | ( A >= B ) 为假 |
<= | 检查左操作数的值是否小于或等于右操作数的值,如果是那么条件为真 | ( A <= B ) 为真 |
下面的代码简单的演示了这些关系运算符的使用
public class Test { public static void main(String[] args) { int a = 10; int b = 20; System.out.println("a == b = " + (a == b) ); System.out.println("a != b = " + (a != b) ); System.out.println("a > b = " + (a > b) ); System.out.println("a < b = " + (a < b) ); System.out.println("b >= a = " + (b >= a) ); System.out.println("b <= a = " + (b <= a) ); }}
编译运行以上 Java 代码,输出结果如下
a == b = falsea != b = truea > b = falsea = a = trueb <= a = false
位运算符
Java 语言支持位运算符
位运算符可以应用于整数类型 (int),长整型 (long),短整型 (short),字符型 (char),和字节型 (byte) 等类型
位运算符作用在所有的位上,并且按位运算
我们假设 a = 60,b = 13,那么它们的二级制和位运算结果如下
A = 0011 1100B = 0000 1101-----------------A & b = 0000 1100A | B = 0011 1101A ^ B = 0011 0001~A = 1100 0011
下表列出了 Java 支持的 位运算符
我们假设整数变量 A 的值为 60 和变量 B 的值为 13
操作符 | 描述 | 示例 |
---|---|---|
& | 如果相对应位都是1,则结果为1,否则为 0 | ( A & B ) 得到 12,即 0000 1100 |
| | 如果相对应位都是0,则结果为 0,否则为 1 | ( A | B ) 得到 61,即 0011 1101 |
^ | 如果相对应位值相同,则结果为0,否则为 1 | (A ^ B)得到49,即 0011 0001 |
〜 | 按位补运算符翻转操作数的每一位 即 0 变成 1,1 变成 0 | ( ~A ) 得到 -61,即1100 0011 |
<< | 按位左移运算符 左操作数按位左移右操作数指定的位数 | A << 2 得到 240,即 1111 0000 |
>> | 按位右移运算符 左操作数按位右移右操作数指定的位数 | A >> 2 得到 15 即 1111 |
>>> | 按位右移补零操作符 左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充 | A>>>2 得到 15 即 0000 1111 |
下面的范例简单的演示了这些位操作符的使用
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 ); }}
编译运行以上 Java 代码,输出结果如下
a & b = 12a | b = 61a ^ b = 49~a = -61a <> 15a >>> 15
逻辑运算符
下表列出了 Java 支持的逻辑运算符的基本运算
假设布尔变量 A 为真,变量 B 为假
操作符 | 描述 | 示例 |
---|---|---|
&& | 称为逻辑与运算符 当且仅当两个操作数都为真,条件才为真 | ( A && B ) 为假 |
|| | 称为逻辑或操作符 如果任何两个操作数任何一个为真,条件为真 | ( A | |B ) 为真 |
! | 称为逻辑非运算符。用来反转操作数的逻辑状态 如果条件为 true,则逻辑非运算符将得到 false | !(A && B) 为真 |
下面的范例演示了这些逻辑运算符的使用
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)); }}
编译运行以上 Java 代码,输出结果如下
a && b = falsea || b = true!(a && b) = true
短路逻辑运算符
当使用 与逻辑运算符 ( && ) 时,在两个操作数都为 true 时,结果才为 true
但是当得到第一个操作为 false 时,其结果就必定是 false,这时候就不会再判断第二个操作了
public class LuoJi{ public static void main(String[] args){ int a = 5;//定义一个变量; boolean b = (a<4)&&(a++<10); System.out.println("使用短路逻辑运算符的结果为"+b); System.out.println("a的结果为"+a); }}
编译运行以上 Java 范例,输出结果如下
使用短路逻辑运算符的结果为 falsea的结果为5
在这段代码中,使用到了短路逻辑运算符( && ),首先判断 a<4 的结果为 false,则 b 的结果必定是 false,所以不再执行第二个操作 a++<10 的判断,所以 a 的值为 5
赋值运算符
下表列出了 Java 语言支持的赋值运算符
操作符 | 描述 | 示例 |
---|---|---|
= | 简单的赋值运算符,将右操作数的值赋给左侧操作数 | C = A + B将把A + B得到的值赋给C |
+= | 加和赋值操作符,将左操作数和右操作数相加赋值给左操作数 | C += A 等价于 C = C + A |
-= | 减和赋值操作符,将左操作数和右操作数相减赋值给左操作数 | C -= A 等价于 C = C -A |
*= | 乘和赋值操作符,将左操作数和右操作数相乘赋值给左操作数 | C *= A 等价于 C = C * A |
/= | 除和赋值操作符,将左操作数和右操作数相除赋值给左操作数 | C /= A 等价于 C = C / A |
%= | 取模和赋值操作符,将左操作数和右操作数取模后赋值给左操作数 | C %= A 等价于 C = 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 |
下面的范例演示了这些运算符的使用
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 >>= a = " + c ); c &= a ; System.out.println("c &= 2 = " + c ); c ^= a ; System.out.println("c ^= a = " + c ); c |= a ; System<