Java基础学习(二):Java中的变量和常量、final(重点)、运算、字符串

目录

相关文章

一、Java中的变量和常量

java是强类型语言。
每一个变量都要明确的声明它的类型。

1. 变量

变量名规则

  • 由字母或字母与数字组成;
  • 字母有大小写区分

变量初始化

  • 指第一次赋值
int a;//声明变量
a = 10;//变量赋值

也可以将变量的声明和初始化写在一起:

int a = 10;

变量分局部变量和全局变量

  • 局部变量:定义在方法中的变量,该变量只能在该方法中使用,没有默认值,变量名不能重名
    public static void change(){
    	int a = 10;//变量a定义在了change()方法中,只能在change()方法中使用
    	System.out.println(a);
    }
    
  • 全局变量:定义在类下,该变量可以在所以方法中使用,有默认值
    • int默认值为0
    • 浮点数默认值为0.0
    • char类型默认值为空字符
    • 布尔类型默认值为false
    • 引用类型默认值为空
      public class Text{
      	int a = 10;//变量a定义在了Text类下
      	public static void change(){
      		System.out.println(a);//能在change()方法中访问到变量a
      	}
      }
      
  • 两种变量均存在,且局部变量和全局变量变量名重复了,局部变量优先
    public class Text{
    	int a = 10;
    	public static void change(){
    		int a = 100;
    		System.out.println(a);//输出:100
    	}
    }
    

2. 常量

  • 常量声明的时候必须要赋值
  • 只能赋值一次,指除了第一次赋值外,后续不能在赋值,不再变的量
  • 使用final修饰
  • 常量名使用全大写,例如:static final double PI = 3.14;

二、final(重点)

  • 修饰的基本类型不可以第二次赋值;
  • 修饰的引用类型不可以第二次改变指向;
  • 修饰的类不可以被继承;
  • 修饰的方法不可以被重写;
  • 防止指令重排序,遏制流水线优化,可以保证多线程并发场景下的可见性;
  • 通常与static一起用。

三、运算

1. 基本运算符

  • 加+、减-、乘*、除/、取余%
  • 注意:
    • 除法中,两个数都是整数,商只保留整数部分;左右两边至少有一个带小数,商为浮点数
      System.out.println(5/2);//输出:2
      System.out.println(5.0/2);//输出:2.5
      System.out.println(5/2.0);//输出:2.5
      
    • 整数/0,报错;浮点数/0,报Infinity(无穷大的意思)
      System.out.println(8/0);//输出:报错
      System.out.println(8.0/0);//输出:Infinity
      

数学函数

Math类

  • 平方根:sqrt()
  • 平方:pow( , )
    • 默认使用double类型存储
      System.out.println(Math.sqrt(21));//计算21的平方根
      System.out.println(Math.pow(21,2);//计算21的平方
      

StrictMath 类

  • Math类相同的方法
    double result = StrictMath.sqrt(2);  // 严格数学运算
    

BigDecimal 类

  • 用于高精度十进制运算
  • 解决浮点数精度问题
  • 提供精确的加减乘除运算
    BigDecimal a = new BigDecimal("0.1");
    BigDecimal b = new BigDecimal("0.2");
    BigDecimal sum = a.add(b);  // 精确得到0.3
    

BigInteger 类

  • 处理任意精度整数运算
  • 适用于超出long范围的整数计算
  • valueOf()方法:是一个静态工厂方法,将基本数据类型的long值转换为 BigInteger 对象
    • public static BigInteger valueOf(long val)
  • multiply()方法:用于计算两个 BigInteger 的乘积,返回一个新的 BigInteger 对象
    • public BigInteger multiply(BigInteger val)
      BigInteger big1 = new BigInteger("12345678901234567890");
      BigInteger big2 = BigInteger.valueOf(987654321L);
      BigInteger product = big1.multiply(big2);
      

2. 自增和自减运算符

++运算:

  • 单独放在一行没区别
    int a = 10;
    a++;//输出:10
    ++a;//输出:10
    
  • 直接赋值给变量,有区别
    • 放在元素前:先运算+1,在赋值
      int a = 10;
      int b = ++a;//输出:11
      //先运算:a = a + 1 = 11
      //在赋值:b = a = 11
      
    • 放在运算后:先赋值,在运算+1
      int a = 10;
      int b = a++;//输出:10
      //先赋值:b = a = 10
      
  • 在一次操作中,如果有两个等号对一个变量进行赋值,只认第一个等号
    int a = 10;
    a = a++;//输出:10  先赋值:a=a 在运算:a=a+1
    a = ++a;//输出:11  先运算:a=a+1 在赋值:a=a
    //先赋值:b = a = 10
    

--运算:与++运算同理。

3. 结合赋值和运算符

二元运算符:+=、-=、*=、/=
+=运算:

int a = 10;
a = a + 20;
//等价于
a += 20;

关系运算符和逻辑运算符经常用在条件判断中。

4. 关系运算符

  • 大于>
  • 小于<
  • 大于等于>=
  • 小于等于<=
  • 不等于!=
  • 等于=

示例:

int a = 10;
int b = 20;
if(a>b){
	System.out.println("a");
}else{
	System.out.println("b");
}//输出:b

5. 逻辑运算符

  • 逻辑与&&:两个条件都要为真,结果才为真
  • 逻辑或||:两个条件中只要有一个为真,结果就为真
  • 逻辑与和逻辑或为短路逻辑与和短路逻辑或,逻辑与中,第一个条件为假,后面的条件就不再执行了
  • 一般用在引用类型的数据、链表,避免一些有风险的代码
    示例1:
int a = 10;
int b = 20;
int c = 30;
if(a<b&&a>c){
	System.out.println("a");
}else{
	System.out.println("b");
}//输出:b

示例2:

String str = null;
if(str!=null&&str.length()>10){
	System.out.println("a");
}else{
	System.out.println("b");
}//输出:b

6. 位运算

针对于二进制数据的运算,都是补码运算。

  • 按位与&(and):两位数运算,上下都为1,结果为1;上下有0,结果为0
    00011010
    00011111
    ------------
    00011010
    
  • 按位或|(or):两位数运算,上下都为0,结果为0;上下有1,结果为1
    00011010
    00011111
    ------------
    00011111
    
  • 按位异或^(xor):两位数运算,上下不同,结果为1;上下相同,结果为0
    00011010
    00011111
    ------------
    00000101
    
  • 按位取反~(not):针对一位数
    00011010
    ------------
    11100101
    

应用题1:给一个二进制的数0101x001,想知道第四位给的是什么数?
解决方案:与运算,任何数与1进行与运算,得到的都是任何数它本身
让0101x001二进制与00001000进行与运算,上下都为1,结果为1;上下有0,结果为0
如果结果为0,x为0;如果结果为1,x为1

0101x001
00001000
------------
0000 000

应用题2:不借第三方变量,如何实现两个数据交换?
解决方案:异或运算

int a = 5;//二进制:0000 0101
int b = 3;//二进制:0000 0011
a = a^b;  //   a = 0000 0110(上面两个进行异或运算)
b = a^b;  //   b = 0000 0101(第二个与a进行异或运算)
a = a^b;  //   a = 0000 0011(a和b进行异或运算)
System.out.println(a);//输出:3
System.out.println(b);//输出:5

问题:为什么有位运算?
与CPU底层相关联。
CPU底层用的都是半导体电路,设计了下面几种半导体电路:
CPU半导体电路

7. 移位运算

移几位,补几位的0,超过位数,删除多余的0

  • 左移<<(变大):往左移,右边补0,左边删0
    示例10000 0010      往左移30000 0010 000  右边补30,超出80001 0000      删除左边的三个0
    示例24*8=4*2^3     往左移动三位
    0000 0100     4的二进制
    0000 0100 000 右边补三个0
    0010 0000     超出8位,左边删除30
    示例34*9=4*8+1=4*2^3+4*2^0
    0000 0100     4的二进制
    4*2^3  --> 左移3位,右边补30,左边删30 --> 0010 0000
    4*2^0  --> 不移动  --> 0000 0100
    相加:
    0010 0000
    0000 0100
    ------------
    0010 0100  --> 32+4=36
    
  • 右移>>(变小):往右移,左边补0,右边删0
    System.out.println(8>>2);//输出:2
    
    • 有符号右移>>:正数,左边补0;复数,左边补1
      示例1:负数(使用补码运算,源码转为反码,反码+1==补码)
      System.out.println(-8>>2);//输出:-2
      -8  --> 源码:1000 1000  --> 反码:11110111 --> 反码+11111 1000 --> 补码:1111 1000
      1111 1000     往右移211 1111 1000  左边补21
      1111 1110     超出8位,右边删20
      补码:1111 1110  --> 补码-11111 1101 --> 反码:1000 0010  --> 源码:1000 0010
      示例2:正数(源码==补码)
      System.out.println(8>>2);//输出:2
      8  --> 源码:0000 1000  -->补码:0000 1000
      0000 1000     往右移200 0000 1000  左边补20
      0000 0010     超出8位,右边删20
      补码:0000 0010  --> 源码:0000 0010
      
    • 无符号右移>>>:无论是正数还是负数,左边均补0
      System.out.println(-8>>>2);//输出:1073741822
      上面举例使用的都是byte类型的数据,实际上默认使用的是int类型数据
      10000000 00000000 00000000 00001000       -8int类型的源码
      11111111 11111111 11111111 11110111       -8的反码
      11111111 11111111 11111111 11111000       -8的的补码
      00 11111111 11111111 11111111 11111000    左边补20
      00111111 11111111 11111111 11111110       超出32位,右边删20
      00111111 11111111 11111111 11111110       正数的源码==补码  --> 1073741822
      

四、字符串

  • 是引用类型中的特殊情况

1. 定义方式:

  • 方式一:直接赋值
    String a = "demo";//底层就是一个数组
    
  • 方式二:面向对象的赋值
    String b = new String("demo");
    
  • 两者的区别:
    区别
  • 判断两个字符串是否相等,就是判断是否指向同一空间,从下面的内存图中可以看出:a和b指向的是同一空间,a和c指向的空间不同,c和d指向的空间也不同
    String a = "demo";
    String b = "demo";
    String c = new String("demo");
    String d = new String("demo");
    System.out.println(a==b);//输出:true
    System.out.println(a==c);//输出:false
    System.out.println(c==d);//输出:false
    
    判断是否相等

2. 字符串可使用的方法

  • equals()方法:检测字符串是否相等
    String a = new String("demo");
    String b = new String("demo");
    System.out.println(a.equals(b));//输出:true
    
  • 替换:replace(old,new)
    String a = new String("demo");
    System.out.println(a.replace("o","x"));//输出:demx
    
  • 拆分:split()
    String a = new String("demo");
    String[] arr = b.split("e")//根据e进行拆分
    System.out.println(Arrays.toString(arr));//输出:[d,mo]
    
  • 字符串的查询与比较
    • 获取字符串长度:length()
      String a = "demo";
      int len = a.length();//输出:4
      
    • 获取指定位置字符:charAt()
      String a = "demo";
      char ch = a.charAt(1);//输出:'d'
      
    • 查找字符位置:indexOf()
      String a = "demo";
      int pos1 = str.indexOf('e');     // 1
      int pos2 = str.indexOf("em");    // 1
      int pos3 = str.indexOf('m', 2);  // 从索引2开始找 → 2
      
    • 从后向前查找:lastIndexOd()
      String a = "demo";
      int lastPos = str.lastIndexOf('e');//输出:1
      
    • 字典序比较:compareTo(String)
      int diff = "apple".compareTo("banana");  // 负数(a<b)
      
    • 是否包含子串:contains()
      String a = "demo";
      boolean hasEll = str.contains("emo");  // true
      
  • 字符串操作
    • 截取子串:substring()
      String a = "demo";
      String sub1 = str.substring(1);     //输出:"emo"
      String sub2 = str.substring(1,3);   //输出:"em" (含头不含尾)
      
    • 连接字符串:concat(String)
      String a = "Hello";
      String newStr = str.concat(" World");  //输出:"Hello World"
      
    • 大小写转换:toLowerCase()/toUpperCase()
      String a = "demo";
      String upper = str.toUpperCase();  //输出:"DEMO"
      
    • 取出首位空白:trim()
      String a = "  demo  ".trim();  //输出:"demo"
      
    • 增强版取出首位空白:strip()
      String a = "demo";
      String stripped = "\u2000demo\u2000".strip();  //输出:"demo"
      
  • 字符串检查
    • 是否空字符串:isEmpty()
      boolean empty = "".isEmpty();  // true
      
    • 是否空白字符串:isBlank()(java 11+)
      boolean blank = "   ".isBlank();  // true
      
    • 开头/结尾检查:startsWith()/endWith()
      String a = "demo";
      boolean starts = str.startsWith("d");  // true
      boolean ends = str.endsWith("mo");      // true
      
  • 字符串转换
    • 转为字符数组:toCharArray()
      String a = "demo";
      char[] chars = str.toCharArray();  // ['d','e','m','o']
      
    • 转为字节数组:getBytes()
      byte[] bytes = str.getBytes();          // 默认编码
      byte[] utf8 = str.getBytes(StandardCharsets.UTF_8);
      
    • 格式化字符串:format()
      String formatted = String.format("Name: %s, Age: %d", "Alice", 25);
      
  • 字符串拼接:+join()
    String joined = String.join("-", "A","B","C");  // "A-B-C"
    
  • 分隔为行流:lines()
    long lineCount = "Line1\nLine2".lines().count();  // 2
    
  • 重复字符串:repeat(int)
    String repeated = "Ab".repeat(3);  // "AbAbAb"
    

3. 不可变字符串

不可变字符串:不能在源地址直接修改

String a = "demo";
String b = new String("demo");

原因:底层是数组,数组在声明空间的时候,是要提前说明空间的大小
但是,可以拼接

String a = "demo";
String b = "123";
String c = a + b;
String d = "demo123";
System.out.println(c);//输出:"demo123"
System.out.println(c==d);//输出:false  指向的不是同一空间

拼接

编译:javac 文件名 --> 生成编译文件
执行:java 编译文件名
反编译:javap -c 编译文件名

String a = "demo"+"123";//a指向demo的空间,123的空间没有被指向,被优化,与demo合并,因此a指向的是demo123的空间
String b = "demo123";
System.out.println(a==b);//输出:true  指向的是同一空间

4. 可变字符串

  • StringBuffer:线程安全(可作用于多线程)
    • 有加锁解锁的过程,加锁,等修改完,才能访问,运行稍慢一些
  • StringBuilder:线程不安全 (可作用于单线程)
    StringBuilder a = new StringBuilder("demo");
    System.out.println(a);//输出:'demo'
    
  • 追加:append()方法
    StringBuilder a = new StringBuilder("demo");
    StringBuilder b = a.append("123");
    System.out.println(a);//输出:'demo123'  在源地址上追加
    System.out.println(a==b);//输出:true
    
  • 插入内容:insert()
    StringBuilder a = new StringBuilder("demo");
    sb.insert(4, " test");  // "demo test"
    
  • 删除子序列:delete(int start,int end)
    StringBuilder a = new StringBuilder("demo");
    sb.delete(2, 3);  // 删除索引2-3的内容,输出:"de"
    
  • 删除指定字符deleteCharAt()
    StringBuilder a = new StringBuilder("demo");
    sb.deleteCharAt(0);  // 删除第一个字符,输出:"emo"
    
  • 替换内容:replace(int start, int end, String str)
    StringBuilder a = new StringBuilder("demo");
    sb.replace(0, 2, "Hi");  // 替换索引0-2的内容,输出:"Himo"
    
  • 反转字符串:reverse()
    StringBuilder a = new StringBuilder("demo");
    sb.reverse();  // 反转字符串内容,输出:"omed"
    

扩展:
时间戳:currentTimeMillis()

long start = System.currentTimeMillis();
String a = "";
for(int i=0;i<10000;i++){
	a = a + "1";
}
long end= System.currentTimeMillis();
System.out.println(end-start);//输出:4860

long start1 = System.currentTimeMillis();
StringBuffer a1 = new StringBuffer("");
for(int i=0;i<10000;i++){
	a1.append("1");
}
long end1= System.currentTimeMillis();
System.out.println(end1-start1);//输出:1

将数据进行分页,每页都有一个地址,传输每页的地址,可读取每页中的内容。
上述代码中

  • String处代码,每次+1,都要在堆区开辟一个新空间,并回收旧空间;加10000个1,就需要开辟10000次新空间,回收10000次旧空间。
  • StringBuffer底层是数组,可以扩容,在一个内存页中不断扩容追加,不用开辟新空间和销毁旧空间的过程。
  • 因此,StringBuffer比String速度块。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值