Day11
static关键字
由static关键字修饰的变量即为静态变量
成员变量分两种:
-
实例变量:没有static修饰,属于对象,存储于堆中,有几个对象就有几份,由实例化的对象访问
-
静态变量:static修饰,属于类,存储在方法区中,只有一份,由类名访问
对象所共享的数据使用static修饰
class Aoo{
int a;//实例变量
static int b;//静态变量
}
示例:
public class StaticVar {
int a;
static int b;
StaticVar(){
a++;
b++;
}
void show(){
System.out.println("a = " + a + " b = " + b);
}
}
public class StaticDemo {
public static void main(String[] args) {
StaticVar staticVar = new StaticVar();
staticVar.show();
StaticVar staticVar1 = new StaticVar();
staticVar1.show();
StaticVar staticVar2 = new StaticVar();
staticVar2.show();
}
}
输出结果:
a = 1 b = 1
a = 1 b = 2
a = 1 b = 3
分析:
静态代码块
- 类加载到内存的时候就会执行静态代码块,一个类只加载一次,所以静态代码块只执行一次
- 静态代码块的执行顺序:
静态代码块 > 静态变量 > 构造代码块 > 构造方法
使用场景:初始化/加载静态资源
静态方法
访问实例变量和实例方法需要对象调用,this可以充当中间对象;
静态变量不需要对象调用,直接使用类名调用即可;
静态方法中没有隐式this,即没有中间对象,所以无法调用实例变量和实例方法,但是可以直接访问静态变量
实例方法中访问静态变量可以直接访问实例变量和静态变量,因为有隐式this作为对象调用实例
- static修饰的方法即为静态方法
- 属于类,存储在方法区,只有一份
- 常通过类名访问
public class StaticMethod {
int a; //实例变量,实例对象访问
static int b; //静态变量,类名访问
public static void main(String[] args) {
StaticMethod sm = new StaticMethod();
sm.show();
}
void show(){ //实例方法,有隐式this
System.out.println(this.a);
System.out.println(StaticMethod.b);
}
static void test(){ //静态方法,无隐式this
//System.out.println(this.a);//错误,静态方法中不能使用this
//System.out.println(a); //错误,静态方法中没有this,所以无法不能使用实例变量
System.out.println(b); //静态方法中可以直接调用静态变量
//show(); //错误,静态方法中不能使用实例方法
}
}
static final常量
- 必须声明的同时初始化,不嫩先声明再初始化
- 常通过类名来访问,不可改变
- 常量名全部大写
- 编译器编译时,会将常量直接替换为具体的数,效率高
- 当在程序中永远不变的数据可以使用static常量
枚举
- 是一种引用类型
- 枚举类型的对象数目是固定的,常用于定义一组常量,季节/星期/订单状态……
- 枚举的构造方法默认为私有的
- 枚举第一行罗列枚举对象名称
枚举的使用
枚举的定义
public enum Seasons {
//编译后自动生成,底层自动实现
// public static final Seasons SPRING = new Seasons();
// public static final Seasons SUMMER = new Seasons();
// public static final Seasons AUTUMN = new Seasons();
// public static final Seasons WINTER = new Seasons();
SPRING,
SUMMER,
AUTUMN,
WINTER;
//编译后自动生成
// private Seasons() {}
}
常用api
season.name()
Seasons.values()
public class EnumTest {
public static void main(String[] args) {
Seasons season = Seasons.SPRING;//直接使用枚举类类名获取枚举对象
System.out.println(season.name());//获取枚举对象的值
Seasons[] seasons = Seasons.values();//获取枚举所有对象的值
Arrays.stream(seasons).forEach(System.out::println);
switch (season){ //switch常与枚举搭配
case SPRING:
System.out.println("春天");
break;
case AUTUMN:
System.out.println("秋天");
break;
case SUMMER:
System.out.println("夏天");
break;
case WINTER:
System.out.println("冬天");
break;
}
}
}
Day12
String类
String特点
- String是不可变对象
- java.lang.String使用了final修饰,不能被继承
- 字符串底层封装了字符数组及针对字符数组的操作算法
- 字符串一段创建,对象内容不可改变,连接字符串会创建新对象
- Java字符串在内存中采用Unicode编码方式,任何一个字符对应两个字节的定长编码
String常量池
公共对象,不能修改,只有直接量赋值才会存入字符串常量池中
Java内存空间
- Java为了提高性能,直接量字符串创建后会缓存在字符串常量池中
- 对于重复出现的字符串直接量,JVM会首先在常量池中查找,若存在即返回该对象来重用,不会重新生成
public static void main(String[] args) {
String s1 = "123abc";//字符串常量池中首次创建对象
String s2 = "123abc";//重用对象
System.out.println(s1 == s2);//true
String s3 = "123abc";//重用对象
System.out.println(s1 == s3);//true
//使用new会强制创建新对象,Java不推荐使用new创建字符串
String s4 = new String("123abc");
System.out.println(s1 == s4);//false
//字符串为不可变
s1 = s1 + "!"; //拼接内容会创建新对象,不会在原对象(常量池中对象)上修改
System.out.println(s1);//123abc!
System.out.println(s2);//123abc
System.out.println(s3);//123abc
}
编译器预计算特性
- 当运算符两侧均为直接量时,编译器会自动将运算结果直接写入字节码,而非创建新对象
- 使用直接量拼接对于某些场景会增加代码可读性
String s5 = "123abc";
String s6 = "123" + "abc";//s6重用字符串常量池对象
System.out.println(s5 == s6);//true
String s7 = "123";
String s8 = s7 + "abc";//JVM不会跨行识别,有一侧为变量,所以不会触发预编译
System.out.println("s8 == s6" + (s8 == s6));//false
常用方法
内存编码及长度
- String在内存中采用Unicode编码,每个字符占两个字节
- 任何一个字符(中文/英文/空格……)都选一个字符长度
- ***length()***方法用于获取字符长度(空格也计入其中)
String str = "Hello World!";
int length = str.length();
System.out.println("字符串的长度是:" + length);//12
检索字符位置
- ***IndexOf(String str)***方法用于实现在字符串中检索另一个字符串首次出现的位置
- 检索成功则返回首次出现位置的坐标,检索失败则返回-1
String str = "think in java";
int index = str.indexOf("in");
System.out.println(index); // 输出 2
int index02 = str.indexOf("IN");
System.out.println(index02);// 输出 -1,因为字母"IN"大写
-
String提供了几个重载的IndexOf()方法:
-
IndexOf(String str, int fromIndex)
两个参数的含义
- 目标字符串
- 开始检索的位置坐标
String str = "think in java"; int index03 = str.indexOf("in", 3); System.out.println(index03);// 输出 6,从索引3开始搜索"in"
-
lastIndexOf(String str)
输出目标字符串最后一次出现的位置坐标
String str = "think in java"; int index04 = str.lastIndexOf("in"); System.out.println(index04);// 输出 6,输出最后一次出现的索引位置
-
获取(截取)字串
***subString()***方法用于截取指定范围内的字符串子串
subString()的两种重载方法
- subString(int start):截取从start开始到末尾的字符串
- subString(int start, int end):截取从指定位置start开始到指定结束位置end的字符串,含左不含右
String str ="www.peng.com";
//截取从指定位置开始到最后的字符串
System.out.println("str.substring(4) = " + str.substring(4));
//截取从指定位置开始到指定结束位置end的字符串,含左不含右
System.out.println("str.substring(4,8) = " + str.substring(4, 8));
案例——获取网址中的域名
需求:在所提供的网址中提取域名,例如"http://www.tedu.com.cn"中提取“tedu”
实现:
private static String getHostName(String line) {
int startIndex = line.indexOf(".")+1;//获取第一个点后的第一个字符的下标
int endIndex = line.indexOf(".", startIndex);//获取第一个点下标的下一个点的下标
if (startIndex > 0 && endIndex > 0) {
return line.substring(startIndex+1,endIndex);
}
return null;
}
去除两侧空白
trim()方法用去去除字符串两侧的空白(空字符串)
注:只去除两侧,中间空白不去
String str = " Hello World ";
System.out.println("原始字符串:" + str);
// 去除字符串两端的空格
System.out.println(str.trim());
定位字符位置
charAt(char ch)方法用于定位指定字符在字符串中的位置
String str = "abcdefg";
for (int i = 0; i < str.length(); i++) {
System.out.print(str.charAt(i)+" ");
}
检测字符串的开始与结尾
区分大小写,返回true或false
可以用于检验网址格式是否合法
- boolean startWith(String str):用于检验目标字符串是不是以指定字符串开始
- boolean endWith(String str):用于检验目标字符串是不是以指定字符串结尾
String str = "hello world";
boolean startCheck = str.startsWith("he");
boolean endCheck = str.endsWith("d");
System.out.println(startCheck); //true
System.out.println(endCheck); //true
改变字符大小写
只转变英文,不改变其他字符
可以用于验证码验证
- toUpperCase():将字符串中的英文转换为全大写
- toLowerCase():将字符串中的英文转换为全小写
- equalsIgnoreCase():忽略大小写进行字符串比较
//验证码校验
String code = "a9Db5EcF";
System.out.println("请输入验证码:" + code);
Scanner sc = new Scanner(System.in);
String input = sc.nextLine();
if(input.toUpperCase().equals(code.toUpperCase())){
System.out.println("验证码正确");
}else{
System.out.println("验证码错误");
}
//思路二
if (input.equalsIgnoreCase(code)){
System.out.println("验证码正确");
}
valueOf()
该方法为静态方法,使用String类名调用即可
- String类提供了若干的静态的重载方法valueOf
- valueOf()用于将其他类型转换为字符串类型
int a = 123;
String s = String.valueOf(s);
- 转字符串的思路二
int a = 123;
String s = a + "";