首页 > 编程语言 >第二部分 Java基本语法

第二部分 Java基本语法

时间:2024-10-20 08:50:04浏览次数:3  
标签:Java 变量 int 第二 System 语法 println public out

第二部分 Java基本语法

一个main方法头文件包含如下:

2.1 标识符

Java 所有的组成部分都需要名字。类名、变量名以及方法名都被称为标识符。

关于 Java 标识符,有以下几点需要注意:

  • 所有的标识符都应该以字母(A-Z 或者 a-z),美元符($)、或者下划线(_)开始
  • 首字符之后可以是字母(A-Z 或者 a-z),美元符($)、下划线(_)或数字的任何字符组合
  • 关键字不能用作标识符
  • 标识符是大小写敏感的
  • 合法标识符举例:age、$salary、_value、__1_value
  • 非法标识符举例:123abc、-salary

2.2 修饰符

像其他语言一样,Java可以使用修饰符来修饰类中方法和属性。主要有两类修饰符:

  • 访问控制修饰符 : default, public , protected, private
  • 非访问控制修饰符 : final, abstract, static, synchronized
2.2.1 访问控制修饰符

Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。

  • default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
  • private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
  • public : 对所有类可见。使用对象:类、接口、变量、方法
  • protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)

我们可以通过以下表来说明访问权限:

修饰符当前类同一包内子孙类(同一包)子孙类(不同包)其他包
publicYYYYY
protectedYYYY/N(说明N
defaultYYYNN
privateYNNNN
2.2.1.1 默认访问修饰符-不使用任何关键字

如果在类、变量、方法或构造函数的定义中没有指定任何访问修饰符,那么它们就默认具有默认访问修饰符。

默认访问修饰符的访问级别是包级别(package-level),即只能被同一包中的其他类访问。

// MyClass.java
 
class MyClass {  // 默认访问修饰符
 
    int x = 10;  // 默认访问修饰符
 
    void display() {  // 默认访问修饰符
        System.out.println("Value of x is: " + x);
    }
}
 
// MyOtherClass.java
 
class MyOtherClass {
    public static void main(String[] args) {
        MyClass obj = new MyClass();
        obj.display();  // 访问 MyClass 中的默认访问修饰符变量和方法
    }
}
2.2.1.2 私有访问修饰符-private

私有访问修饰符是最严格的访问级别,所以被声明为 private 的方法、变量和构造方法只能被所属类访问,并且类和接口不能声明为 private

声明为私有访问类型的变量只能通过类中公共的 getter 方法被外部类访问。

Private 访问修饰符的使用主要用来隐藏类的实现细节和保护类的数据。

下面的类使用了私有访问修饰符:

public class Logger {
   private String format;
   public String getFormat() {
      return this.format;
   }
   public void setFormat(String format) {
      this.format = format;
   }
}
2.2.1.3 公有访问修饰符-public

被声明为 public 的类、方法、构造方法和接口能够被任何其他类访问。

如果几个相互访问的 public 类分布在不同的包中,则需要导入相应 public 类所在的包。由于类的继承性,类所有的公有方法和变量都能被其子类继承。

以下函数使用了公有访问控制:

public static void main(String[] arguments) {
   // ...
}

Java 程序的 main() 方法必须设置成公有的,否则,Java 解释器将不能运行该类。

2.2.1.4 受保护的访问修饰符-protected

protected 需要从以下两个点来分析说明:

  • 子类与基类在同一包中:被声明为 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。

2.2.1.5 访问控制和继承

请注意以下方法继承的规则:

  • 父类中声明为 public 的方法在子类中也必须为 public。
  • 父类中声明为 protected 的方法在子类中要么声明为 protected,要么声明为 public,不能声明为 private。
  • 父类中声明为 private 的方法,不能够被子类继承。
2.2.2 非访问修饰符

为了实现一些其他的功能,Java 也提供了许多非访问修饰符。

static 修饰符,用来修饰类方法和类变量。

final 修饰符,用来修饰类、方法和变量,final 修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的。

abstract 修饰符,用来创建抽象类和抽象方法。

synchronized 和 volatile 修饰符,主要用于线程的编程。

2.2.2.1 static 修饰符
  • 静态变量:

    static 关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝。 静态变量也被称为类变量。局部变量不能被声明为 static 变量。

  • 静态方法:

    static 关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据,然后计算这些数据。

对类变量和方法的访问可以直接使用 classname.variablenameclassname.methodname 的方式访问。

如下例所示,static 修饰符用来创建类方法和类变量。

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");
   }
}
2.2.2.2 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 方法的主要目的是防止该方法的内容被修改。

如下所示,使用 final 修饰符声明方法。

public class Test{
    public final void changeName(){
       // 方法体
    }
}

final 类

final 类不能被继承,没有类能够继承 final 类的任何特性。

public final class Test {
   // 类体
}
2.2.2.3 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(){
          .........
      }
}
2.2.2.4 synchronized 修饰符

synchronized 关键字声明的方法同一时间只能被一个线程访问。synchronized 修饰符可以应用于四个访问修饰符。

public synchronized void showDetails(){
.......
}
2.2.2.5 transient 修饰符

序列化的对象包含被 transient 修饰的实例变量时,java 虚拟机(JVM)跳过该特定的变量。

该修饰符包含在定义变量的语句中,用来预处理类和变量的数据类型。

public transient int limit = 55;   // 不会持久化
public int b; // 持久化
2.2.2.6 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,所以该循环会停止。

2.3 Java关键字与保留字

首先我们需要明确一下,关键字一定是保留字,但是保留字不一定是关键字。

如:true、false是保留字但是不是关键字。

在Java中,关键字具有特殊含义,是语法的一部分。

保留字不能用于常量、变量、和任何标识符的名称。

下面是Java中常用的保留字。

2.4 Java注释

Java 注释主要有三种类型:

  • 单行注释
  • 多行注释
  • 文档注释
2.4.1 单行注释

单行注释用 //

// 这是一个单行注释
int x = 10; // 初始化一个变量x为10
2.4.2 多行注释

多行注释以 /* 开始,以 */ 结束:

/*
这是一个多行注释
可以用来注释多行代码
*/
/*
int a = 10;
int b = 20;
int c = 30;
*/
2.4.3 文档注释

文档注释以 /** 开始,以 **/ 结束,通常出现在类、方法、字段等的声明前面,用于生成代码文档,这种注释可以被工具提取并生成 API 文档,如 JavaDoc。

/**
 * 这是一个文档注释示例
 * 它通常包含有关类、方法或字段的详细信息
 */
public class MyClass {
    // 类的成员和方法
}

2.5 Java数据类型

Java 的两大数据类型:

  • 内置数据类型(基本数据类型)
  • 引用数据类型

换句话来说,基本数据类型在栈中存储的是具体的值。而引用数据类型存储的是一个地址。

2.5.1 基本数据类型

Java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。

下图是八种基本数据类型:

基本数据类型基本数据类型的变量

int a = 10;

我们需要明白的是,int是基本数据类型,而a是一个int型变量。

2.5.2 引用数据类型
  • 在Java中,引用类型的变量非常类似于C/C++的指针。引用类型指向一个对象,指向对象的变量是引用变量。这些变量在声明时被指定为一个特定的类型,比如 Employee、Puppy 等。变量一旦声明后,类型就不能被改变了。
  • 对象、数组都是引用数据类型。
  • 所有引用类型的默认值都是null。
  • 一个引用变量可以用来引用任何与之兼容的类型。
  • 例子:Site site = new Site("Guangy")

例如:假如我定义了一个Student类,对于下面这句代码。

Student student1 = new Student();

可以理解为Student是引用数据类型,而student1是引用数据类型的变量。

2.6 变量与常量

2.6.1 变量

在 Java 语言中,所有的变量在使用前必须声明。

声明变量的基本格式如下:

type identifier [ = value][, identifier [= value] ...] ;

格式说明:

  • type – 数据类型。
  • identifier – 是变量名,可以使用逗号 , 隔开来声明多个同类型变量。

以下列出了一些变量的声明实例。注意有些包含了初始化过程。

int a, b, c;         // 声明三个int型整数:a、 b、c
int d = 3, e = 4, f = 5; // 声明三个整数并赋予初值
byte z = 22;         // 声明并初始化 z
String s = "Guangy";  // 声明并初始化字符串 s
double pi = 3.14159; // 声明了双精度浮点型变量 pi
char x = 'x';        // 声明变量 x 的值是字符 'x'。
2.6.1.1 Java 语言支持的变量类型
  • **局部变量(Local Variables):**局部变量是在方法、构造函数或块内部声明的变量,它们在声明的方法、构造函数或块执行结束后被销毁,局部变量在声明时需要初始化,否则会导致编译错误。

    public void exampleMethod() {
        int localVar = 10; // 局部变量
        // ...
    }
    
  • **实例变量(非静态变量)(Instance Variables):**实例变量是在类中声明,但在方法、构造函数或块之外,它们属于类的实例,每个类的实例都有自己的副本,如果不明确初始化,实例变量会被赋予默认值(数值类型为0,boolean类型为false,对象引用类型为null)。

    public class ExampleClass {
        int instanceVar; // 实例变量
    }
    
  • 类变量(静态变量)(Class Variables):类变量是在类中用 static 关键字声明的变量,它们属于类而不是实例,所有该类的实例共享同一个类变量的值,类变量在类加载时被初始化,而且只初始化一次。

    public class ExampleClass {
        static int classVar; // 类变量
    }
    
  • **参数变量(Parameters):**参数是方法或构造函数声明中的变量,用于接收调用该方法或构造函数时传递的值,参数变量的作用域只限于方法内部。

    public void exampleMethod(int parameterVar) {
        // 参数变量
        // ...
    }
    

以下实例中定义了一个 GuangyTest 类,其中包含了一个成员变量 instanceVar 和一个静态变量 staticVar。

method() 方法中定义了一个参数变量 paramVar 和一个局部变量 localVar。在方法内部,我们将局部变量的值赋给成员变量,将参数变量的值赋给静态变量,然后打印出这些变量的值。

在 main() 方法中,我们创建了一个 GuangyTest 对象,并调用了它的 method() 方法。

public class GuangyTest {
    // 成员变量
    private int instanceVar;
    // 静态变量
    private static int staticVar;
    
    public void method(int paramVar) {
        // 局部变量
        int localVar = 10;
        
        // 使用变量
        instanceVar = localVar;
        staticVar = paramVar;
        
        System.out.println("成员变量: " + instanceVar);
        System.out.println("静态变量: " + staticVar);
        System.out.println("参数变量: " + paramVar);
        System.out.println("局部变量: " + localVar);
    }
    
    public static void main(String[] args) {
        GuangyTest v = new GuangyTest();
        v.method(20);
    }
}

运行以上代码,输出如下:

成员变量: 10
静态变量: 20
参数变量: 20
局部变量: 10

Java 参数变量

Java 中的参数变量是指在方法或构造函数中声明的变量,用于接收传递给方法或构造函数的值。参数变量与局部变量类似,但它们只在方法或构造函数被调用时存在,并且只能在方法或构造函数内部使用。

Java 方法的声明语法如下:

accessModifier returnType methodName(parameterType parameterName1, parameterType parameterName2, ...) {
    // 方法体
}
  • parameterType – 表示参数变量的类型。
  • parameterName – 表示参数变量的名称。

在调用方法时,我们必须为参数变量传递值,这些值可以是常量、变量或表达式。

方法参数变量的值传递方式有两种:值传递引用传递

  • **值传递:**在方法调用时,传递的是实际参数的值的副本。当参数变量被赋予新的值时,只会修改副本的值,不会影响原始值。Java 中的基本数据类型都采用值传递方式传递参数变量的值。
  • **引用传递:**在方法调用时,传递的是实际参数的引用(即内存地址)。当参数变量被赋予新的值时,会修改原始值的内容。Java 中的对象类型采用引用传递方式传递参数变量的值。

以下是一个简单的例子,展示了方法参数变量的使用:

public class GuangyTest {
    public static void main(String[] args) {
        int a = 10, b = 20;
        swap(a, b); // 调用swap方法
        System.out.println("a = " + a + ", b = " + b); // 输出a和b的值
    }
    
    public static void swap(int x, int y) {
        int temp = x;
        x = y;
        y = temp;
    }
}

运行以上代码,输出如下:

a = 10, b = 20

Java 局部变量

Java 的局部变量是在方法、构造方法或语句块内部声明的变量,其作用域限制在声明它的代码块内部。

局部变量的声明语法为:

type variableName;
  • type – 表示变量的类型。
  • variableName – 表示变量的名称。

说明:

  • 作用域:局部变量的作用域限于它被声明的方法、构造方法或代码块内。一旦代码执行流程离开这个作用域,局部变量就不再可访问。
  • 生命周期:局部变量的生命周期从声明时开始,到方法、构造方法或代码块执行结束时终止。之后,局部变量将被垃圾回收。
  • 初始化:局部变量在使用前必须被初始化。如果不进行初始化,编译器会报错,因为 Java 不会为局部变量提供默认值。
  • 声明:局部变量的声明必须在方法或代码块的开始处进行。声明时可以指定数据类型,后面跟着变量名,例如:int count;
  • 赋值:局部变量在声明后必须被赋值,才能在方法内使用。赋值可以是直接赋值,也可以是通过方法调用或表达式。
  • 限制:局部变量不能被类的其他方法直接访问,它们只为声明它们的方法或代码块所私有。
  • 内存管理:局部变量存储在 Java 虚拟机(JVM)的栈上,与存储在堆上的实例变量或对象不同。
  • 垃圾回收:由于局部变量的生命周期严格限于方法或代码块的执行,它们在方法或代码块执行完毕后不再被引用,因此JVM的垃圾回收器会自动回收它们占用的内存。
  • 重用:局部变量的名称可以在不同的方法或代码块中重复使用,因为它们的作用域是局部的,不会引起命名冲突。
  • 参数和返回值:方法的参数可以视为一种特殊的局部变量,它们在方法被调用时初始化,并在方法返回后生命周期结束。

以下是一个简单的例子,展示了局部变量的使用:

public class LocalVariablesExample {
    public static void main(String[] args) {
        int a = 10; // 局部变量a的声明和初始化
        int b;     // 局部变量b的声明
        b = 20;    // 局部变量b的初始化
        
        System.out.println("a = " + a);
        System.out.println("b = " + b);
        
        // 如果在使用之前不初始化局部变量,编译器会报错
        // int c;
        // System.out.println("c = " + c);
    }
}

以上实例中我们声明并初始化了两个局部变量 a 和 b,然后打印出它们的值。注意,如果在使用局部变量之前不初始化它,编译器会报错。

在以下实例中 age 是一个局部变量,定义在 pupAge()方法中,它的作用域就限制在这个方法中:

package com.Guangy.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();
   }
}

以上实例编译运行结果如下:

小狗的年龄是: 7

在下面的例子中 age 变量没有初始化,所以在编译时会出错:

package com.Guangy.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();
   }
}

以上实例编译运行结果如下:

Test.java:4:variable number might not have been initialized
age = age + 7;
         ^
1 error

成员变量(实例变量)

  • 成员变量声明在一个类中,但在方法、构造方法和语句块之外。
  • 当一个对象被实例化之后,每个成员变量的值就跟着确定。
  • 成员变量在对象创建的时候创建,在对象被销毁的时候销毁。
  • 成员变量的值应该至少被一个方法、构造方法或者语句块引用,使得外部能够通过这些方式获取实例变量信息。
  • 成员变量可以声明在使用前或者使用后。
  • 访问修饰符可以修饰成员变量。
  • 成员变量对于类中的方法、构造方法或者语句块是可见的。一般情况下应该把成员变量设为私有。通过使用访问修饰符可以使成员变量对子类可见。
  • 成员变量具有默认值。数值型变量的默认值是0,布尔型变量的默认值是 false,引用类型变量的默认值是 null。变量的值可以在声明时指定,也可以在构造方法中指定;
  • 成员变量可以直接通过变量名访问。但在静态方法以及其他类中,就应该使用完全限定名:ObjectReference.VariableName

成员变量的声明语法为:

accessModifier type variableName;
  • accessModifier --表示访问修饰符,可以是 public、protected、private 或默认访问级别(即没有显式指定访问修饰符)。
  • type – 表示变量的类型。
  • variableName – 表示变量的名称。

与局部变量不同,成员变量的值在创建对象时被分配,即使未对其初始化,它们也会被赋予默认值,例如 int 类型的变量默认值为 0,boolean 类型的变量默认值为 false。

成员变量可以通过对象访问,也可以通过类名访问(如果它们是静态成员变量)。如果没有显式初始化成员变量,则它们将被赋予默认值。可以在构造函数或其他方法中初始化成员变量,或者通过对象或类名访问它们并设置它们的值。

以下实例我们声明了两个成员变量 a 和 b,并对其进行了访问和设置。注意,我们可以通过对象访问成员变量,也可以通过类名访问静态成员变量。

public class GuangyTest {
      private int a; // 私有成员变量a
      public String b = "Hello"; // 公有成员变量b
      
      public static void main(String[] args) {
         GuangyTest obj = new GuangyTest(); // 创建对象
          
          obj.a = 10; // 访问成员变量a,并设置其值为10
          System.out.println("a = " + obj.a);
          
          obj.b = "World"; // 访问成员变量b,并设置其值为"World"
          System.out.println("b = " + obj.b);
      }
  }

以上实例编译运行结果如下:

a = 10
b = World

以下实例我们声明了两个成员变量 name 和 salary,并对其进行了访问和设置。

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("Guangy");
      empOne.setSalary(1000.0);
      empOne.printEmp();
   }
}

以上实例编译运行结果如下:

$ javac Employee.java 
$ java Employee
名字 : Guangy
薪水 : 1000.0

类变量(静态变量)

Java 中的静态变量是指在类中定义的一个变量,它与类相关而不是与实例相关,即无论创建多少个类实例,静态变量在内存中只有一份拷贝,被所有实例共享。

静态变量在类加载时被创建,在整个程序运行期间都存在。

定义方式

静态变量的定义方式是在类中使用 static 关键字修饰变量,通常也称为类变量。

以下实例中我们定义一个静态变量 count ,其初始值为 0:

public class MyClass {
    public static int count = 0;
    // 其他成员变量和方法
}

访问方式

由于静态变量是与类相关的,因此可以通过类名来访问静态变量,也可以通过实例名来访问静态变量。

MyClass.count = 10; // 通过类名访问
MyClass obj = new MyClass();
obj.count = 20; // 通过实例名访问

生命周期

静态变量的生命周期与程序的生命周期一样长,即它们在类加载时被创建,在整个程序运行期间都存在,直到程序结束才会被销毁。因此,静态变量可以用来存储整个程序都需要使用的数据,如配置信息、全局变量等。

初始化时机

静态变量在类加载时被初始化,其初始化顺序与定义顺序有关。

如果一个静态变量依赖于另一个静态变量,那么它必须在后面定义。

public class MyClass {
    public static int count1 = 0;
    public static int count2 = count1 + 1;
    // 其他成员变量和方法
}

上面的例子中,count1 要先于 count2 初始化,否则编译时会报错。

常量和静态变量的区别

常量也是与类相关的,但它是用 final 关键字修饰的变量,一旦被赋值就不能再修改。与静态变量不同的是,常量在编译时就已经确定了它的值,而静态变量的值可以在运行时改变。另外,常量通常用于存储一些固定的值,如数学常数、配置信息等,而静态变量通常用于存储可变的数据,如计数器、全局状态等。

总之,静态变量是与类相关的变量,具有唯一性和共享性,可以用于存储整个程序都需要使用的数据,但需要注意初始化时机和与常量的区别。

静态变量的访问修饰符

静态变量的访问修饰符可以是 public、protected、private 或者默认的访问修饰符(即不写访问修饰符)。

需要注意的是,静态变量的访问权限与实例变量不同,因为静态变量是与类相关的,不依赖于任何实例。

静态变量的线程安全性

Java 中的静态变量是属于类的,而不是对象的实例。因此,当多个线程同时访问一个包含静态变量的类时,需要考虑其线程安全性。

静态变量在内存中只有一份拷贝,被所有实例共享。因此,如果一个线程修改了静态变量的值,那么其他线程在访问该静态变量时也会看到修改后的值。这可能会导致并发访问的问题,因为多个线程可能同时修改静态变量,导致不确定的结果或数据一致性问题。

为了确保静态变量的线程安全性,需要采取适当的同步措施,如同步机制、原子类或 volatile 关键字,以便在多线程环境中正确地读取和修改静态变量的值。

静态变量的命名规范

静态变量(也称为类变量)的命名规范通常遵循驼峰命名法,并且通常使用全大写字母,单词之间用下划线分隔,并且要用 static 关键字明确标识。

  • 使用驼峰命名法: 静态变量的命名应该使用驼峰命名法,即首字母小写,后续每个单词的首字母大写。例如:myStaticVariable
  • 全大写字母: 静态变量通常使用全大写字母,单词之间用下划线分隔。这被称为"大写蛇形命名法"(Upper Snake Case)。例如:MY_STATIC_VARIABLE
  • 描述性: 变量名应该是有意义的,能够清晰地表达该变量的用途。避免使用单个字符或不具有明确含义的缩写。
  • 避免使用缩写: 尽量避免使用缩写,以提高代码的可读性。如果使用缩写是必要的,确保广泛理解,并在注释中进行解释。
public class MyClass {
    // 使用驼峰命名法
    public static int myStaticVariable;

    // 使用大写蛇形命名法
    public static final int MAX_SIZE = 100;

    // 避免使用缩写
    public static final String employeeName;

    // 具有描述性的变量名
    public static double defaultInterestRate;
}

静态变量的使用场景

静态变量通常用于以下场景:

  • 存储全局状态或配置信息
  • 计数器或统计信息
  • 缓存数据或共享资源
  • 工具类的常量或方法
  • 单例模式中的实例变量

以下实例定义了一个 AppConfig 类,其中包含了三个静态变量 APP_NAME、APP_VERSION 和 DATABASE_URL,用于存储应用程序的名称、版本和数据库连接URL。这些变量都被声明为 final,表示它们是不可修改的常量。

在 main() 方法中,我们打印出了这些静态变量的值。

public class AppConfig {
    public static final String APP_NAME = "MyApp";
    public static final String APP_VERSION = "1.0.0";
    public static final String DATABASE_URL = "jdbc:mysql://localhost:3306/mydb";
    
    public static void main(String[] args) {
        System.out.println("Application name: " + AppConfig.APP_NAME);
        System.out.println("Application version: " + AppConfig.APP_VERSION);
        System.out.println("Database URL: " + AppConfig.DATABASE_URL);
    }
}

以上实例编译运行结果如下:

Application name: MyApp
Application version: 1.0.0
Database URL: jdbc:mysql://localhost:3306/mydb

可以看到,这些静态变量存储的全局配置信息可以在整个程序中使用,并且不会被修改。这个例子展示了静态变量的另一个常见应用,通过它我们可以很方便地存储全局配置信息,或者实现其他需要全局共享的数据。

以下实例定义了一个 Counter 类,其中包含了一个静态变量 count,用于记录创建了多少个 Counter 对象。

每当创建一个新的对象时,构造方法会将计数器加一。静态方法 getCount() 用于获取当前计数器的值。

在 main() 方法中,我们创建了三个 Counter 对象,并打印出了计数器的值。

public class Counter {
    private static int count = 0;
    
    public Counter() {
        count++;
    }
    
    public static int getCount() {
        return count;
    }
    
    public static void main(String[] args) {
        Counter c1 = new Counter();
        Counter c2 = new Counter();
        Counter c3 = new Counter();
        System.out.println("目前为止创建的对象数: " + Counter.getCount());
    }
}

以上实例编译运行结果如下:

目前为止创建的对象数: 3

可以看到,计数器记录了创建了三个对象。这个例子展示了静态变量的一个简单应用,通过它我们可以很方便地统计对象的创建次数,或者记录其他需要全局共享的数据。

2.6.1.2 变量命名规则

在 Java 中,不同类型的变量(例如实例变量、局部变量、静态变量等)有一些命名规则和约定。

遵循一些基本规则,这有助于提高代码的可读性和维护性。

以下是各种变量命名规则的概述:

  • 使用有意义的名字: 变量名应该具有清晰的含义,能够准确地反映变量的用途。避免使用单个字符或无意义的缩写。
  • 驼峰命名法(Camel Case): 在变量名中使用驼峰命名法,即将每个单词的首字母大写,除了第一个单词外,其余单词的首字母都采用大写形式。例如:myVariableName
  • 避免关键字: 不要使用 Java 关键字(例如,class、int、boolean等)作为变量名。
  • 区分大小写: Java 是大小写敏感的,因此变量名中的大小写字母被视为不同的符号。例如,myVariablemyvariable 是两个不同的变量。
  • 不以数字开头: 变量名不能以数字开头,但可以包含数字。
  • 遵循命名约定: 对于不同类型的变量(局部变量、实例变量、静态变量等),可以采用不同的命名约定,例如使用前缀或后缀来区分。

局部变量

  • 使用驼峰命名法。
  • 应该以小写字母开头。
  • 变量名应该是描述性的,能够清晰地表示其用途。
int myLocalVariable;

实例变量(成员变量)

  • 使用驼峰命名法。
  • 应该以小写字母开头。
  • 变量名应该是描述性的,能够清晰地表示其用途。
private int myInstanceVariable;

静态变量(类变量)

  • 使用驼峰命名法,应该以小写字母开头。
  • 通常也可以使用大写蛇形命名法,全大写字母,单词之间用下划线分隔。
  • 变量名应该是描述性的,能够清晰地表示其用途。
// 使用驼峰命名法
public static int myStaticVariable;

// 使用大写蛇形命名法
public static final int MAX_SIZE = 100;

常量

  • 使用全大写字母,单词之间用下划线分隔。
  • 常量通常使用 final 修饰。
public static final double PI = 3.14;

参数

  • 使用驼峰命名法。
  • 应该以小写字母开头。
  • 参数名应该是描述性的,能够清晰地表示其用途。
public void myMethod(int myParameter) {
    // 方法体
}

类名

  • 使用驼峰命名法。
  • 应该以大写字母开头。
  • 类名应该是描述性的,能够清晰地表示其用途。
public class MyClass {
    // 类的成员和方法
}
2.6.2 常量

在Java中,常量是一种特殊的变量,其值一旦被初始化设置后就不能被改变。常量通常用于存储那些在程序运行期间不应该改变的值。

一般我们使用 final 关键字来声明一个常量

当将 final 关键字应用于一个变量时,这个变量就变成了常量。对于基本数据类型,这意味着它的值不能被改变;对于引用类型,这意味着引用不能指向另一个对象,但被引用的对象本身是可以被修改的(除非对象本身也是不可变的)。

声明如下:

final int MAX_COUNT = 100; // 基本数据类型的常量
final String NAME = "ConstantName"; // 引用类型的常量

虽然常量名也可以用小写,但为了便于识别,通常使用大写字母表示常量。

字面量可以赋给任何内置类型的变量。例如:

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空字符 (0x0)
\s空格 (0x20)
\t制表符
"双引号
单引号
\反斜杠
\ddd八进制字符 (ddd)
\uxxxx16进制Unicode字符 (xxxx)
2.6.3 数据类型转换

整型、实型(常量)、字符型数据可以混合运算。运算中,不同类型的数据先转化为同一类型,然后进行运算。

转换从低级到高级。

低  ------------------------------------>  高

byte,short,char—> int —> long—> float —> double 

数据类型转换必须满足如下规则:

    1. 不能对boolean类型进行类型转换。
    1. 不能把对象类型转换成不相关类的对象。
    1. 在把容量大的类型转换为容量小的类型时必须使用强制类型转换。
    1. 转换过程中可能导致溢出或损失精度,例如:
    int i =128;   
    byte b = (byte)i;
    

    因为 byte 类型是 8 位,最大值为127,所以当 int 强制转换为 byte 类型时,值 128 时候就会导致溢出。

    1. 浮点数到整数的转换是通过舍弃小数得到,而不是四舍五入,例如:
    (int)23.7 == 23;        
    (int)-45.89f == -45
    
2.6.3.1 隐式类型转换(自动类型转换)

必须满足转换前的数据类型的位数要低于转换后的数据类型,例如: short数据类型的位数为16位,就可以自动转换位数为32的int类型,同样float数据类型的位数为32,可以自动转换为64位的double类型。

例如:

public class ZiDongLeiZhuan{
        public static void main(String[] args){
            char c1='a';//定义一个char类型
            int i1 = c1;//char自动类型转换为int
            System.out.println("char自动类型转换为int后的值等于"+i1);
            char c2 = 'A';//定义一个char类型
            int i2 = c2+1;//char 类型和 int 类型计算
            System.out.println("char类型和int计算后的值等于"+i2);
        }
}
char自动类型转换为int后的值等于97
char类型和int计算后的值等于66

**解析:**c1 的值为字符 a ,查 ASCII 码表可知对应的 int 类型值为 97, A 对应值为 65,所以 i2=65+1=66

2.6.3.2 显式类型转换(强制类型转换)
  • 条件是转换的数据类型必须是兼容的。
  • 格式:(type)value type是要强制类型转换后的数据类型 实例:
public class ForceTransform {
    public static void main(String[] args){
        int i1 = 123;
        byte b = (byte)i1;//强制类型转换为byte
        System.out.println("int强制类型转换为byte后的值等于"+b);
    }
}

运行结果:

int强制类型转换为byte后的值等于123

隐含强制类型转换

  • 整数的默认类型是 int。
  • 小数默认是 double 类型浮点型,在定义 float 类型时必须在数字后面跟上 F 或者 f。

2.7 字面量

2.7.2 什么是字面量

实际上,字面量就是我们给一个变量或者常量直接赋值时的数值。例如:

int a = 10;

这里有一个整形变量a。我们将10赋值给了这个变量,这个10我们可以称之为整形字面量。

同样的,

String str = "abc";

对于如上所示的代码中,我们有一个引用数据类型的变量str。我们将abc赋值给了这个变量,这个abc我们可以称之为引用数据类型的字面量。

2.8 运算符

计算机的最基本用途之一就是执行数学运算,作为一门计算机语言,Java也提供了一套丰富的运算符来操纵变量。我们可以把运算符分成以下几组:

  • 算术运算符
  • 关系运算符
  • 位运算符
  • 逻辑运算符
  • 赋值运算符
  • 其他运算符
2.8.1 算术运算符

算术运算符用在数学表达式中,它们的作用和在数学中的作用一样。下表列出了所有的算术运算符。

表格中的实例假设整数变量A的值为10,变量B的值为20:

操作符描述例子
+加法 - 相加运算符两侧的值A + B 等于 30
-减法 - 左操作数减去右操作数A – B 等于 -10
*乘法 - 相乘操作符两侧的值A * B等于200
/除法 - 左操作数除以右操作数B / A等于2
取余 - 左操作数除以右操作数的余数B%A等于0
++自增: 操作数的值增加1B++ 或 ++B 等于 21(区别详见下文)
自减: 操作数的值减少1B-- 或 --B 等于 19(区别详见下文)
2.8.1.1 算术运算符(基础运算)

下面的简单示例程序演示了算术运算符。复制并粘贴下面的 Java 程序并保存为 Test.java 文件,然后编译并运行这个程序:

public class Test {
 
  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) );
  }
}

以上实例编译运行结果如下:

a + b = 30
a - b = -10
a * b = 200
b / a = 2
b % a = 0
c % a = 5
a++   = 10
a--   = 11
d++   = 25
++d   = 27
2.8.1.2 自增自减运算符

1、自增(++)自减(–)运算符是一种特殊的算术运算符,在算术运算符中需要两个操作数来进行运算,而自增自减运算符是一个操作数。

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);
    }
}

运行结果为:

进行自增运算后的值等于4
进行自减运算后的值等于2

解析:

  • int b = ++a; 拆分运算过程为: a=a+1=4; b=a=4, 最后结果为b=4,a=4
  • int d = --c; 拆分运算过程为: c=c-1=2; d=c=2, 最后结果为d=2,c=2

2、前缀自增自减法(++a,–a): 先进行自增或者自减运算,再进行表达式运算。

3、后缀自增自减法(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);
    }
}

运行结果为:

自增运算符前缀运算后a=6,x=12
自增运算符后缀运算后b=6,y=10
2.8.2 关系运算符

下表为Java支持的关系运算符

表格中的实例整数变量A的值为10,变量B的值为20:

运算符描述例子
==检查如果两个操作数的值是否相等,如果相等则条件为真。(A == B)为假。
!=检查如果两个操作数的值是否相等,如果值不相等则条件为真。(A != B) 为真。
>检查左操作数的值是否大于右操作数的值,如果是那么条件为真。(A> B)为假。
<检查左操作数的值是否小于右操作数的值,如果是那么条件为真。(A <B)为真。
>=检查左操作数的值是否大于或等于右操作数的值,如果是那么条件为真。(A> = B)为假。
<=检查左操作数的值是否小于或等于右操作数的值,如果是那么条件为真。(A <= B)为真。

下面的简单示例程序演示了关系运算符。复制并粘贴下面的Java程序并保存为Test.java文件,然后编译并运行这个程序:

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) );
  }
}

以上实例编译运行结果如下:

a == b = false
a != b = true
a > b = false
a < b = true
b >= a = true
b <= a = false
2.8.2.1 == 运算符

== 运算符比较的是变量内存储的值,对于基本数据类型和引用数据类型比较的内容并不相同。

  • 比较基本数据类型

    由于基本数据类型的变量内存储的是具体的值,因此 == 运算符用来判断值是否相等。

  • 比较引用数据类型

    引用数据类型存储的是地址值,因此 == 运算符比较的是地址值是否一致,即比较两引用数据类型的变量是否引用的为同一个对象。

2.8.3 位运算符

Java定义了位运算符,应用于整数类型(int),长整型(long),短整型(short),字符型(char),和字节型(byte)等类型。

位运算符作用在所有的位上,并且按位运算。假设a = 60,b = 13;它们的二进制格式表示将如下:

A = 0011 1100
B = 0000 1101
-----------------
A&B = 0000 1100
A | B = 0011 1101
A ^ B = 0011 0001
~A= 1100 0011

下表列出了位运算符的基本运算,假设整数变量 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

下面的简单示例程序演示了位运算符。复制并粘贴下面的Java程序并保存为Test.java文件,然后编译并运行这个程序:

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
2.8.4 逻辑运算符

下表列出了逻辑运算符的基本运算,假设布尔变量A为真,变量B为假

操作符描述例子
&&称为逻辑与运算符。当且仅当两个操作数都为真,条件才为真。(A && B)为假。
| |称为逻辑或操作符。如果任何两个操作数任何一个为真,条件为真。(A | | B)为真。
称为逻辑非运算符。用来反转操作数的逻辑状态。如果条件为true,则逻辑非运算符将得到false。!(A && B)为真。

下面的简单示例程序演示了逻辑运算符。复制并粘贴下面的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

短路逻辑运算符

当使用与逻辑运算符时,在两个操作数都为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);
    }
}

运行结果为:

使用短路逻辑运算符的结果为false
a的结果为5

解析: 该程序使用到了短路逻辑运算符(&&),首先判断 a<4 的结果为 false,则 b 的结果必定是 false,所以不再执行第二个操作 a++<10 的判断,所以 a 的值为 5。

2.8.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 与 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

下面的简单示例程序演示了赋值运算符。复制并粘贴下面的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
2.8.6 条件运算符(?:)(三元运算符)

条件运算符也被称为三元运算符。该运算符有3个操作数,并且需要判断布尔表达式的值。该运算符的主要是决定哪个值应该赋值给变量。

variable x = (expression) ? value if true : value if false
public class Test {
   public static void main(String[] args){
      int a , b;
      a = 10;
      // 如果 a 等于 1 成立,则设置 b 为 20,否则为 30
      b = (a == 1) ? 20 : 30;
      System.out.println( "Value of b is : " +  b );
 
      // 如果 a 等于 10 成立,则设置 b 为 20,否则为 30
      b = (a == 10) ? 20 : 30;
      System.out.println( "Value of b is : " + b );
   }
}

以上实例编译运行结果如下:

Value of b is : 30
Value of b is : 20
2.8.7 instanceof 运算符

该运算符用于操作对象实例,检查该对象是否是一个特定类型(类类型或接口类型)。

instanceof运算符使用格式如下:

( Object reference variable ) instanceof  (class/interface type)

如果运算符左侧变量所指的对象,是操作符右侧类或接口(class/interface)的一个对象,那么结果为真。

下面是一个例子:

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);
   }
}

以上实例编译运行结果如下:

true
2.8.8 Java运算符优先级

当多个运算符出现在一个表达式中,谁先谁后呢?这就涉及到运算符的优先级别的问题。在一个多运算符的表达式中,运算符优先级不同会导致最后得出的结果差别甚大。

例如,(1+3)+(3+2)*2,这个表达式如果按加号最优先计算,答案就是 18,如果按照乘号最优先,答案则是 14。

再如,x = 7 + 3 * 2;这里x得到13,而不是20,因为乘法运算符比加法运算符有较高的优先级,所以先计算3 * 2得到6,然后再加7。

下表中具有最高优先级的运算符在的表的最上面,最低优先级的在表的底部。

类别操作符关联性
后缀() [] . (点操作符)左到右
一元expr++ expr–从左到右
一元++expr --expr + - ~ !从右到左
乘性* /%左到右
加性+ -左到右
移位>> >>> <<左到右
关系> >= < <=左到右
相等== !=左到右
按位与左到右
按位异或^左到右
按位或|左到右
逻辑与&&左到右
逻辑或| |左到右
条件?:从右到左
赋值= + = - = * = / =%= >> = << =&= ^ = | =从右到左
逗号左到右

2.9 选择语句

Java 中的选择语句允许程序根据条件的不同执行不同的代码块。常用的选择语句有if-else、switch-case两种。

2.9.1 if 语句

一个 if 语句包含一个布尔表达式和一条或多条语句。

语法

if 语句的语法如下:

if(布尔表达式)
{
   //如果布尔表达式为true将执行的语句
}

如果布尔表达式的值为 true,则执行 if 语句中的代码块。

public class Test {
 
   public static void main(String args[]){
      int x = 10;
 
      if( x < 20 ){
         System.out.print("这是 if 语句");
      }
   }
}

以上代码编译运行结果如下:

这是 if 语句
2.9.2 if…else语句

if 语句后面可以跟 else 语句,当 if 语句的布尔表达式值为 false 时,else 语句块会被执行。

语法

if…else 的用法如下:

if(布尔表达式){
   //如果布尔表达式的值为true
}else{
   //如果布尔表达式的值为false
}

例如:

public class Test {
 
   public static void main(String args[]){
      int x = 30;
 
      if( x < 20 ){
         System.out.print("这是 if 语句");
      }else{
         System.out.print("这是 else 语句");
      }
   }
}

以上代码编译运行结果如下:

这是 else 语句
2.9.3 if…else if…else 语句

if 语句后面可以跟 else if…else 语句,这种语句可以检测到多种可能的情况。

使用 if,else if,else 语句的时候,需要注意下面几点:

  • if 语句至多有 1 个 else 语句,else 语句在所有的 else if 语句之后。
  • if 语句可以有若干个 else if 语句,它们必须在 else 语句之前。
  • 一旦其中一个 else if 语句检测为 true,其他的 else if 以及 else 语句都将跳过执行。

语法

if…else 语法格式如下:

if(布尔表达式 1){
   //如果布尔表达式 1的值为true执行代码
}else if(布尔表达式 2){
   //如果布尔表达式 2的值为true执行代码
}else if(布尔表达式 3){
   //如果布尔表达式 3的值为true执行代码
}else {
   //如果以上布尔表达式都不为true执行代码
}

例如:

public class Test {
   public static void main(String args[]){
      int x = 30;
 
      if( x == 10 ){
         System.out.print("Value of X is 10");
      }else if( x == 20 ){
         System.out.print("Value of X is 20");
      }else if( x == 30 ){
         System.out.print("Value of X is 30");
      }else{
         System.out.print("这是 else 语句");
      }
   }
}

以上代码编译运行结果如下:

Value of X is 30
2.9.4 嵌套的 if…else 语句

使用嵌套的 if…else 语句是合法的。也就是说你可以在另一个 if 或者 else if 语句中使用 if 或者 else if 语句。

语法

嵌套的 if…else 语法格式如下:

if(布尔表达式 1){
   如果布尔表达式 1的值为true执行代码
   if(布尔表达式 2){
      如果布尔表达式 2的值为true执行代码
   }
}

你可以像 if 语句一样嵌套 else if…else。

例如:

public class Test {
 
   public static void main(String args[]){
      int x = 30;
      int y = 10;
 
      if( x == 30 ){
         if( y == 10 ){
             System.out.print("X = 30 and Y = 10");
          }
       }
    }
}

以上代码编译运行结果如下:

X = 30 and Y = 10
2.9.5 switch case 语句

switch case 语句判断一个变量与一系列值中某个值是否相等,每个值称为一个分支。

语法

switch case 语句语法格式如下:

switch(expression){
    case value :
       //语句
       break; //可选
    case value :
       //语句
       break; //可选
    //你可以有任意数量的case语句
    default : //可选
       //语句
}

switch case 语句有如下规则:

  • switch 语句中的变量类型可以是: byte、short、int 或者 char。从 Java SE 7 开始,switch 支持字符串 String 类型了,同时 case 标签必须为字符串常量或字面量。
  • switch 语句可以拥有多个 case 语句。每个 case 后面跟一个要比较的值和冒号。
  • case 语句中的值的数据类型必须与变量的数据类型相同,而且只能是常量或者字面常量。
  • 当变量的值与 case 语句的值相等时,那么 case 语句之后的语句开始执行,直到 break 语句出现才会跳出 switch 语句。
  • 当遇到 break 语句时,switch 语句终止。程序跳转到 switch 语句后面的语句执行。case 语句不必须要包含 break 语句。如果没有 break 语句出现,程序会继续执行下一条 case 语句,直到出现 break 语句。
  • switch 语句可以包含一个 default 分支,该分支一般是 switch 语句的最后一个分支(可以在任何位置,但建议在最后一个)。default 在没有 case 语句的值和变量值相等的时候执行。default 分支不需要 break 语句。

switch case 执行时,一定会先进行匹配,匹配成功返回当前 case 的值,再根据是否有 break,判断是否继续输出,或是跳出判断。

例如:

public class Test {
   public static void main(String args[]){
      //char grade = args[0].charAt(0);
      char grade = 'C';
 
      switch(grade)
      {
         case 'A' :
            System.out.println("优秀"); 
            break;
         case 'B' :
         case 'C' :
            System.out.println("良好");
            break;
         case 'D' :
            System.out.println("及格");
            break;
         case 'F' :
            System.out.println("你需要再努力努力");
            break;
         default :
            System.out.println("未知等级");
      }
      System.out.println("你的等级是 " + grade);
   }
}

以上代码编译运行结果如下:

良好
你的等级是 C

如果 case 语句块中没有 break 语句时,JVM 并不会顺序输出每一个 case 对应的返回值,而是继续匹配,匹配不成功则返回默认 case。

public class Test {
   public static void main(String args[]){
      int i = 5;
      switch(i){
         case 0:
            System.out.println("0");
         case 1:
            System.out.println("1");
         case 2:
            System.out.println("2");
         default:
            System.out.println("default");
      }
   }
}

以上代码编译运行结果如下:

default

如果 case 语句块中没有 break 语句时,匹配成功后,从当前 case 开始,后续所有 case 的值都会输出。

public class Test {
   public static void main(String args[]){
      int i = 1;
      switch(i){
         case 0:
            System.out.println("0");
         case 1:
            System.out.println("1");
         case 2:
            System.out.println("2");
         default:
            System.out.println("default");
      }
   }
}

以上代码编译运行结果如下:

1
2
default

如果当前匹配成功的 case 语句块没有 break 语句,则从当前 case 开始,后续所有 case 的值都会输出,如果后续的 case 语句块有 break 语句则会跳出判断。

public class Test {
   public static void main(String args[]){
      int i = 1;
      switch(i){
         case 0:
            System.out.println("0");
         case 1:
            System.out.println("1");
         case 2:
            System.out.println("2");
         case 3:
            System.out.println("3"); break;
         default:
            System.out.println("default");
      }
   }
}

以上代码编译运行结果如下:

1
2
3

2.10 循环结构

Java中有三种主要的循环结构:

  • while 循环
  • do…while 循环
  • for 循环
2.11.2 while 循环

while是最基本的循环,它的结构为:

while( 布尔表达式 ) {
  //循环内容
}

只要布尔表达式为 true,循环就会一直执行下去。

例如:

public class Test {
   public static void main(String[] args) {
      int x = 10;
      while( x < 20 ) {
         System.out.print("value of x : " + x );
         x++;
         System.out.print("\n");
      }
   }
}

以上实例编译运行结果如下:

value of x : 10
value of x : 11
value of x : 12
value of x : 13
value of x : 14
value of x : 15
value of x : 16
value of x : 17
value of x : 18
value of x : 19
2.10.2 do…while 循环

对于 while 语句而言,如果不满足条件,则不能进入循环。但有时候我们需要即使不满足条件,也至少执行一次。

do…while 循环和 while 循环相似,不同的是,do…while 循环至少会执行一次。

do {
       //代码语句
}while(布尔表达式);

**注意:**布尔表达式在循环体的后面,所以语句块在检测布尔表达式之前已经执行了。 如果布尔表达式的值为 true,则语句块一直执行,直到布尔表达式的值为 false。

public class Test {
   public static void main(String[] args){
      int x = 10;
 
      do{
         System.out.print("value of x : " + x );
         x++;
         System.out.print("\n");
      }while( x < 20 );
   }
}

以上实例编译运行结果如下:

value of x : 10
value of x : 11
value of x : 12
value of x : 13
value of x : 14
value of x : 15
value of x : 16
value of x : 17
value of x : 18
value of x : 19
2.10.3 for循环

虽然所有循环结构都可以用 while 或者 do…while表示,但 Java 提供了另一种语句 —— for 循环,使一些循环结构变得更加简单。

for循环执行的次数是在执行前就确定的。语法格式如下:

for(初始化; 布尔表达式; 更新) {
    //代码语句
}

关于 for 循环有以下几点说明:

  • 最先执行初始化步骤。可以声明一种类型,但可初始化一个或多个循环控制变量,也可以是空语句。
  • 然后,检测布尔表达式的值。如果为 true,循环体被执行。如果为false,循环终止,开始执行循环体后面的语句。
  • 执行一次循环后,更新循环控制变量。
  • 再次检测布尔表达式。循环执行上面的过程。

例如:

public class Test {
   public static void main(String[] args) {
 
      for(int x = 10; x < 20; x = x+1) {
         System.out.print("value of x : " + x );
         System.out.print("\n");
      }
   }
}

以上实例编译运行结果如下:

value of x : 10
value of x : 11
value of x : 12
value of x : 13
value of x : 14
value of x : 15
value of x : 16
value of x : 17
value of x : 18
value of x : 19
2.10.4 Java 增强 for 循环

Java5 引入了一种主要用于数组的增强型 for 循环。

Java 增强 for 循环语法格式如下:

for(声明语句 : 表达式)
{
   //代码句子
}

**声明语句:**声明新的局部变量,该变量的类型必须和数组元素的类型匹配。其作用域限定在循环语句块,其值与此时数组元素的值相等。

**表达式:**表达式是要访问的数组名,或者是返回值为数组的方法。

public class Test {
   public static void main(String[] args){
      int [] numbers = {10, 20, 30, 40, 50};
 
      for(int x : numbers ){
         System.out.print( x );
         System.out.print(",");
      }
      System.out.print("\n");
      String [] names ={"James", "Larry", "Tom", "Lacy"};
      for( String name : names ) {
         System.out.print( name );
         System.out.print(",");
      }
   }
}

以上实例编译运行结果如下:

10,20,30,40,50,
James,Larry,Tom,Lacy,
2.10.5 break 关键字

break 主要用在循环语句或者 switch 语句中,用来跳出整个语句块。

break 跳出最里层的循环,并且继续执行该循环下面的语句。

语法

break 的用法很简单,就是循环结构中的一条语句:

break;
public class Test {
   public static void main(String[] args) {
      int [] numbers = {10, 20, 30, 40, 50};
 
      for(int x : numbers ) {
         // x 等于 30 时跳出循环
         if( x == 30 ) {
            break;
         }
         System.out.print( x );
         System.out.print("\n");
      }
   }
}

以上实例编译运行结果如下:

10
20
2.10.6 continue 关键字

continue 适用于任何循环控制结构中。作用是让程序立刻跳转到下一次循环的迭代。

在 for 循环中,continue 语句使程序立即跳转到更新语句。

在 while 或者 do…while 循环中,程序立即跳转到布尔表达式的判断语句。

语法

continue 就是循环体中一条简单的语句:

continue;
public class Test {
   public static void main(String[] args) {
      int [] numbers = {10, 20, 30, 40, 50};
 
      for(int x : numbers ) {
         if( x == 30 ) {
        continue;
         }
         System.out.print( x );
         System.out.print("\n");
      }
   }
}

以上实例编译运行结果如下:

10
20
40
50

标签:Java,变量,int,第二,System,语法,println,public,out
From: https://blog.csdn.net/wgy17734894660/article/details/143088167

相关文章

  • Java设计模式——适配器模式
    适配器模式(AdapterPattern)是一种结构型设计模式,它用于将一个类的接口转换成客户端希望的另一个接口,使得原本由于接口不兼容而无法一起工作的类可以协同工作。适配器模式的主要目的是兼容性和重用性,特别是在使用一些已有的类,而它们的接口又不符合要求时。适配器模式的核心思想......
  • JavaScript中的this指向
    1.函数在调用时,JavaScript会默认给this绑定一个值;2.this的绑定和定义的位置(编写的位置)没有关系;3.this的绑定和调用方式以及调用的位置有关系;4.this是在运行时被绑定的;this的绑定规则规则一:默认绑定在函数独立调用时使用默认绑定,可以理解为函数没有被绑定到某个对象上常见......
  • 【Python】最详细--基础语法
    Python是一种强大且易于学习的编程语言,广泛用于各种应用程序的开发,如web开发、数据科学、人工智能等。以下是一些Python的基础知识:1.Python的注释Python的注释用于在代码中添加说明,以提高代码的可读性。注释在代码执行时会被忽略。单行注释:使用#符号标识,#后面的内容被视为......
  • Java的重载和主要内存区
    JAVA的重载​在Java中,重载(Overloading)是指在同一个类中可以定义多个同名的方法,但它们的参数列表必须不同。重载可以通过改变参数的数量、类型或者顺序来实现。重载提高了代码的可读性和灵活性。JAVA重载要满足的条件:在同一个类下:java的重载必须在同一个类之下方法名相同......
  • 【Java】Java面向对象与方法
    1.基本方法1.1.基本定义在Java中,方法即为函数,Java中的方法定义遵循下面的通用格式修饰符返回值方法名(形参列表){方法体}对于基本方法的定义,遵循下面的结构publicstatic返回类型方法名(形参列表){方法体}是否需要返回类型和形参列表需要看该......
  • Java21虚拟线程:我的锁去哪儿了?
    0前言最近的文章中,我们详细介绍了当我们迁移到Java21并将代际ZGC作为默认垃圾收集器时,我们的工作负载是如何受益的。虚拟线程是我们在这次迁移中兴奋采用的另一个特性。对虚拟线程新手,它们被描述为“轻量级线程,大大减少编写、维护和观察高吞吐量并发应用程序的工作量。”......
  • 【Java基础】物理内存&虚拟内存
    前言在Java程序运行过程中,操作系统为其分配了物理内存和虚拟内存。理解这两者的概念有助于明晰内存管理和性能优化。一、物理内存物理内存是指计算机的实际RAM(随机存取存储器)。Java进程在运行时需要向操作系统请求内存资源,操作系统通过分配物理内存来满足Java进程的内存......
  • java锁的问题速通
     1.syncronized底层原理——悲观锁synchronized有对象锁和类锁两种,多个线程中只有一个线程可以获取对象锁,其他线程都会处于阻塞状态synchronized是底层是基于monitor实现的。monitor是C++编写的jvm对象,主要分为owner(这个只会存一个线程的信息,记录当前锁被哪个线程获取了)、ent......
  • java反射机制
    什么是java反射呢,先来看Oracle官方的解释:“ReflectionenablesJavacodetodiscoverinformationaboutthefields,methodsandconstructorsofloadedclasses,andtousereflectedfields,methods,andconstructorstooperateontheirunderlyingcounterparts,......
  • [Java基础] 异常处理机制
    往期回顾[Java基础]基本数据类型[Java基础]运算符[Java基础]流程控制[Java基础]面向对象编程[Java基础]集合框架[Java基础]输入输出流[Java基础]异常处理机制[Java基础]Lambda表达式目录什么是异常处理?异常分类检查型异常非检查型异常(UncheckedExcepti......