首页 > 编程语言 >Java基础语法

Java基础语法

时间:2024-08-02 10:42:10浏览次数:19  
标签:运算符 Java 变量 基础 System 语法 println public out

  • 关键字和保留字

    一、概念

    Java关键字(Key Word): 对Java的编译器有特殊的意义,他们用来表示一种数据类型或者表示程序的结构.

    保留字(Reserve Word):即它们在Java现有版本中没有特殊含义,以后版本可能会作为有特殊含义的词,或者该词虽然在Java中没有特殊含义,以后版本也不打算使用,但在其它语言中有特殊含义,不宜在Java中定义为变量名称等,因为容易混淆。

    注意:关键字和保留字均不能用作变量名、方法名、类名、包名和参数。

    二、具体的保留字

    goto、const。

    三、具体的关键字(51个)

    1.访问修饰符(3个)

    public、protected、private

    作用:用来修饰类(接口、抽象类)、方法、属性、构造方法、常量、主函数

    2.类、接口、抽象类(9个)

    class、interface、abstract——定义

    extends——继承类、implements——实现接口

    new——新建一个对象、super——调用父类方法、this——指代当前对象

    instanceof——通过返回一个布尔值来指出,这个对象是否是这个特定类或者是它的子类的一个实例。

    3.数据类型(13个)

    void——没有返回值

    byte、short、int、long——整型数据

    float、double——浮点型数据

    char——字符型数据

    boolean——判断型数据

    enum——枚举

    null、true、false——值类型

    4.线程(2个)

    synchronized——线程同步(修饰方法、代码块,方法、代码块的同步)

    volatile——线程同步(修饰属性,属性的同步)

    5.异常(5个)

    throw——抛出方法代码中的异常给方法自身。使用位置:方法中间

    throws——抛出方法中的异常给调用者。使用位置:方法外部

    try——捕获{}中代码是否有发生异常

    catch——处理try捕获的异常

    finally——不管有没有异常发生都会执行的代码块

    6.返回(1个)

    return

    7.循环、条件(10个)

    if、else、switch、case、break、default、continue、while、do、for

    8.包(2个)

    package、import

    9.瞬时的(1个)

    transient

    10.断言(1个)

    assert

    11.调用底层代码(C\C++)(1个)

    native

    12、不可变的——final(1个)

    修饰属性、常量、局部变量、参数——作用:数据是不可改变的

    修饰类——作用:修饰的类不能被继承

    修饰普通方法——作用:修饰的方法不能被重写

    13.静态的——static(1个)

    修饰属性、常量

    修饰内部类

    修饰普通方法

    作用:所有使用static关键字修饰的内容会最先执行。static修饰的内容在内存中只有唯一的一份(存储在静态内存空间中)。

    14.格式规范——strictfp(1个)

    修饰类、接口或方法。

    修饰方法时,该方法中所有的float和double表达式都严格遵守FP-strict的限制,符合IEEE-754规范。

    修饰类或接口时,该类中的所有代码,包括嵌套类型中的初始设定值和代码,都将严格地进行计算。

    严格约束意味着所有表达式的结果都必须是 IEEE 754 算法对操作数预期的结果,以单精度和双精度格式表示。

  • 标识符

    标识符含义
    标识符就是我们编程的时候使用的“名字“ , 给类、接口、方法、变量、常量名,包名等起名字的字符序列

    标识符的组成:
    英文大小写字母、数字、下划线( _ )和美元符号( $ ) (可以使用汉字或其他合法字符命名,但是不推荐)

    定义规则(硬性要求)
    不能以数字开头
    不能是关键字
    严格区分大小写
    可以是汉字或其他合法字符命名,但不推荐

    命名规范(非硬性要求)
    类和接口:
    首个字母大写,如果有多个单词,每个单词首字母大写:HelloWorld、Student

    变量和方法:
    首字母小写,如果有多个单词,从第二个单词开始首字母大写:getName、studyJava

    常量名(自定义常量):
    所有字母都大写,多个单词用下划线隔开( _ ) :MAX_VALUE

    包名:
    全部小写,如果有多级,用点号( . )隔开、遵循域名反写的格式:com.liyahui.demo (demo 指 包的功能)

    驼峰命名法

    是指混合使用大小写字母来构成变量和函数的名字例如,下面是分别用骆驼式命名法和下划线法命名的同一个函数:

    printEmployeePaychecks();
    print_employee_paychecks();
    

    第一个函数名使用了骆驼式命名法,函数名中的每一个逻辑断点都有一个大写字母来标记;第二个函数名使用了下划线法,函数名中的每一个逻辑断点都有一个下划线来标记

    骆驼式命名法近年来越来越流行了,在许多新的函数库和Microsoft Windows这样的环境中,它使用得当相多另一方面,下划线法是c出现后开始流行起来的,在许多旧的程序和UNIX这样的环境中,它的使用非常普遍

    驼峰式命名法分为大驼峰式命名规则:FirstName, CamelCase

    小驼峰式命名规则:firstName, camelCase

    [中间不需要空格 - _等分割符]

  • 变量

    在 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 = "runoob";  // 声明并初始化字符串 s 
    double pi = 3.14159; // 声明了双精度浮点型变量 pi 
    char x = 'x';    // 声明变量 x 的值是字符 'x'。
    

    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) {
          // 参数变量
          // ...
      }
      

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

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

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

    实例

    public class RunoobTest {   
    // 成员变量    
    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) {     RunoobTest v = new RunoobTest();         v.method(20);    
     } 
    }
    

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

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

    Java 参数变量

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

    Java 方法的声明语法如下:

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

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

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

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

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

    实例

    public class RunoobTest {
      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.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();   
            }
        }
    

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

    小狗的年龄是: 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();  
       }
     }
    

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

    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 RunoobTest {
       private int a; // 私有成员变量a
       public String b = "Hello"; // 公有成员变量b
       
       public static void main(String[] args) {
         RunoobTest obj = new RunoobTest(); // 创建对象
         
         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,并对其进行了访问和设置。

    Employee.java 文件代码:

    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.0);                empOne.printEmp();  
    }
    }
    

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

    $ javac Employee.java 
    $ java Employee
    名字 : RUNOOB
    薪水 : 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() 方法中,我们打印出了这些静态变量的值。

    AppConfig.java 文件代码:

    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 对象,并打印出了计数器的值。

    Counter.java 文件代码:

    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
    

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

  • 数据类型

    基本数据类型(8种类型)

    img

    引用类型

    1. 强引用(Strong Reference):
      定义: 强引用(Strong Reference)是Java中最为普遍的引用类型。当一个对象被强引用关联时,垃圾回收器不会回收这个对象,即使系统内存不足也不会回收。只有当该对象的强引用被显式地释放,或者不再被任何引用关联时,该对象才会成为垃圾回收的候选对象。
      示例代码:
    public class StrongReferenceExample {
        public static void main(String[] args) {
            // 创建一个对象并建立强引用
            Object obj = new Object(); // 强引用
    // 对象仍然存在,可以正常使用
        System.out.println("Object is still accessible.");
     
        // 解除对对象的强引用
        obj = null;
     
        // 系统内存充足时,垃圾回收器可能不会立即回收
        // 只有在需要释放内存时,垃圾回收器才会回收不再被引用的对象
    }
    }
    

    在这个例子中,创建了一个对象并建立了强引用。即使在解除对对象的强引用后,只要系统内存充足,垃圾回收器不会立即回收对象。强引用使得对象在被引用时一直保持有效,直到引用被显式解除。

    1. 软引用(Soft Reference):
      定义: 软引用用于描述一些还有用但并非必须的对象,在内存不足时可能被垃圾回收。
      示例代码:
     import java.lang.ref.SoftReference;
    
    public class SoftReferenceExample {
        public static void main(String[] args) {
            // 创建一个大对象
            byte[] largeObject = new byte[10 * 1024 * 1024]; // 10MB   
        // 使用软引用关联这个大对象
        SoftReference<byte[]> softReference = new SoftReference<>(largeObject);
     
        // 大对象不再被强引用,但仍然被软引用关联
     
        // 尝试获取软引用关联的对象
        byte[] retrievedObject = softReference.get();
     
        if (retrievedObject != null) {
            System.out.println("对象仍然存在,无需重新创建。");
        } else {
            System.out.println("对象已被回收,需要重新创建。");
        }
    }
    }
    

    在这个例子中,创建了一个10MB大小的大对象,并使用软引用SoftReference与之关联。然后,尝试通过软引用获取对象。如果内存足够,对象就会保留;如果内存不足,垃圾回收器可能会回收该对象。这样,软引用允许在内存不足时释放一些非必要的对象,从而提高系统的内存利用率。

    1. 弱引用(Weak Reference):
      定义: 弱引用(Weak Reference)是Java中一种比强引用更弱的引用类型。当一个对象只被弱引用关联时,在下一次垃圾回收时,该对象就有可能被回收。垃圾回收器会在适当的时候回收仅被弱引用持有的对象,即使内存并不紧张。
      示例代码:
    import java.lang.ref.WeakReference;
    
    public class WeakReferenceExample {
        public static void main(String[] args) {
            // 创建一个对象并建立弱引用
            Object obj = new Object();
            WeakReference<Object> weakRef = new WeakReference<>(obj);
        // 对象仍然存在,可以正常使用
        System.out.println("Object is still accessible: " + weakRef.get());
     
        // 解除对对象的强引用
        obj = null;
     
        // 手动触发垃圾回收
        System.gc();
     
        // 垃圾回收后,对象被回收,弱引用返回null
        System.out.println("Object after garbage collection: " + weakRef.get());
    }
    }
    

    在这个例子中,创建了一个对象并建立了弱引用。解除对对象的强引用后,手动触发垃圾回收。由于只有弱引用关联该对象,垃圾回收器可能会在垃圾回收时回收这个对象。因此,通过弱引用可以更容易地允许对象在合适的时候被回收。

    1. 虚引用(Phantom Reference):
      定义: 虚引用(Phantom Reference)是Java中最弱的引用类型之一,无法通过引用直接获取到对象实例。虚引用主要用于跟踪对象被垃圾回收的状态。当一个对象只被虚引用关联时,其实际上并不影响对象的生命周期,也就是说,垃圾回收器随时可能回收被虚引用关联的对象。
      示例代码:
    import java.lang.ref.PhantomReference;
       import java.lang.ref.ReferenceQueue;
    
    public class PhantomReferenceExample {
        public static void main(String[] args) {
            // 创建一个对象并建立虚引用
            Object obj = new Object();
            ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
            PhantomReference<Object> phantomRef = new PhantomReference<>(obj, referenceQueue);
    // 对象实例不能通过虚引用直接获取
        System.out.println("Object is not accessible: " + phantomRef.get());
     
        // 解除对对象的强引用
        obj = null;
     
        // 手动触发垃圾回收
        System.gc();
     
        // 虚引用将被放入引用队列
        if (referenceQueue.poll() != null) {
            // 在引用队列中发现引用,表示对象已被垃圾回收
            System.out.println("Object has been garbage collected.");
        }
    }
    }
    

    在这个例子中,创建了一个对象并建立了虚引用。由于虚引用无法通过get()方法获取对象实例,对象的生命周期不受虚引用的影响。解除对对象的强引用后,手动触发垃圾回收,虚引用将被放入引用队列。通过监测引用队列中是否有引用,可以了解对象是否已被垃圾回收。虚引用主要用于在对象被回收时执行一些清理操作。

  • 数据类型的转换

    隐式转换

    隐式类型转换也叫做自动类型转换。
    1、规则:
    从存储范围小的类型到存储范围大的类型。

    2、转换方向:
    byte→short(char)→int→long→float→double(这里指的是只有前面的数据类型能随便转换成后面的)
    —实际开发中这样的类型转换很多,但没有为这种转换提供专门的语法,都是由虚拟机自动完成。

    3、例子:
    byte b = 10;short sh = b;这里在赋值时,JVM首先将b的值转换为short类型,然后再赋值给sh。

    显式转换

    显式类型转换也叫做强制类型转换。
    1、规则:
    从存储范围大的类型到存储范围小的类型。

    2、转换方向:
    double→float→long→int→short(char)→byte
    强制类型转换通常都会存储精度的损失,所以使用时需要谨慎。
    —需要在被转换值的前面添加个括号,括号里面写的是希望得到的数据类型。

  • 运算符

    计算机的最基本用途之一就是执行数学运算,作为一门计算机语言,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(区别详见下文)

    实例

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

    自增自减运算符

    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
    

    关系运算符

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

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

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

    实例

    下面的简单示例程序演示了关系运算符。复制并粘贴下面的Java程序并保存为Test.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
    

    位运算符

    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文件,然后编译并运行这个程序:

    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
    

    逻辑运算符

    下表列出了逻辑运算符的基本运算,假设布尔变量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。


    赋值运算符

    下面是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文件,然后编译并运行这个程序:

    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
    

    条件运算符(?:)

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

    variable x = (expression) ? value if true : value if false
    

    实例

    Test.java 文件代码:

    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
    

    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
    

    Java运算符优先级

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

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

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

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

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

标签:运算符,Java,变量,基础,System,语法,println,public,out
From: https://www.cnblogs.com/rehe/p/18338202

相关文章

  • Java的跨平台原理
    Java的跨平台原理目录Java的跨平台原理Java的编译过程字节码Java虚拟机(JVM)跨平台性的工作原理示例编译:运行:关键概念总结​ Java的跨平台特性是其最吸引人的特点之一。Java的设计理念之一就是“一次编写,到处运行”(WriteOnce,RunAnywhere,WORA),这主要得益于Java虚拟机(JVM)和......
  • Java的编译和运行命令
    Java的编译和运行命令目录Java的编译和运行命令Java源文件编译Java源代码运行Java程序示例编译步骤运行步骤注意事项示例:编译和运行包含外部类的程序Java源文件扩展名:.java文件是Java源代码文件的标准扩展名。命名规则:每个Java源文件应该只包含一个公共类(publicclass),且该文......
  • nb python 语法
    在bytesized32的开源代码里面看到了一个玄学内容。whileTrue:try:stream=call_gpt(stream=True,model=model,messages=messages,**kwargs)pbar=tqdm(stream,unit="token",total=kwargs.get("max_tokens",8*1024),leave=......
  • 从表演基础到LLM Roleplay的动作描写
    最近在阅读表演基础的教程时,发现其实是可以迁移到角色扮演的描述上的形体语言什么是形体语言?这是我们首先要解决的问题.人类常常不会不自觉的运用身体部位,并通过这些部位的姿态来表达情感.常见的部位有:面部:皱眉手部:握拳,摊开,合拢,手指肩部:用肩部轻触,耸......
  • idea java 逆向脚本
    逆向脚本target_app="/Users/voidm/Applications/GoLand.app"rewrite_file="$(pwd)/../out/production/java_dev/com/jetbrains/ls/responses/License.class"rewrite_file2="$(pwd)/../out/production/java_dev/com/jetbrains/ls/responses/License\......
  • python需要学习的基础库
    Python在数据分析和机器学习领域非常强大,得益于其丰富的库和框架。以下是一些常用的数据分析和机器学习库,以及推荐的学习资源网站:数据分析库NumPy:提供高性能的多维数组对象和用于处理数组的工具。它是许多科学计算库的基础。学习资源:NumPy官方文档Pandas:为数据分析提供了......
  • 从表演基础到LLM Roleplay的动作描写
    最近在阅读表演基础的教程时,发现其实是可以迁移到角色扮演的描述上的形体语言什么是形体语言?这是我们首先要解决的问题.人类常常不会不自觉的运用身体部位,并通过这些部位的姿态来表达情感.常见的部位有:面部:皱眉手部:握拳,摊开,合拢,手指肩部:用肩部轻触,耸......
  • 计算机视觉库Kornia基础教程
    Kornia是一个用于计算机视觉任务的Python库,它提供了丰富的图像处理和计算机视觉操作接口。本教程将介绍Kornia的基本安装、使用方法以及一些实用的功能示例。一、引言Kornia是一个面向研究人员和开发者的计算机视觉库,它建立在PyTorch之上,旨在简化图像处理和计算机视觉任......
  • FPGA知识基础之--500ms计数器,边沿检测,按键消抖
    目录前言一、边沿检测1.1使用背景1.2方法:打拍法1.2.1背景1.2.2原理1.2.3上升沿二、计数器2.1原理2.2RTL代码三、按键消抖前言一、边沿检测1.1使用背景在我们设计电路时,经常会遇到需要继续检测上升沿和下降沿的电路,因此需要对边沿继续检测1.2方法:打......
  • 轮转数组的Java实现
    轮转数组给定一个整数数组nums,将数组中的元素向右轮转k个位置,其中k是非负数。输入:nums=[1,2,3,4,5,6,7],k=3输出:[5,6,7,1,2,3,4]解释:向右轮转1步:[7,1,2,3,4,5,6]向右轮转2步:[6,7,1,2,3,4,5]向右轮转3步:[5,6,7,1,2,3,4]解法1:把数组看成......