static关键字可以用于修饰类的成员变量、方法和代码块。 static修饰的变量称为静态变量。 static修饰的方法称为静态方法 static修饰的初始化代码块,称为静态代码块。 static修饰的类,静态内部类。
用static修饰的变量叫做静态变量(类变量) 静态变量特征:类的所有对象共享一个静态变量
public class Student { private int id; private String name; private int age; static String country="中国"; // 静态变量 public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void sayHello(){ System.out.println("hello..."); } public int add(int a,int b){ return a+b; } }静态变量内存图
(1)静态变量的特点 加载时机 静态变量随着类的加载而加载 静态变量随着类的加载进方法区,就直接在方法区开辟类储存静态变量的内存空间 静态变量优先于对象的存在 静态变量被所有该类对象所共享 代码层面 可以使用类名直接调用,不需要使用对象名称。 在不创建对象的前提下,仍然可以使用这个静态变量。建议用类名来访问。 (2)静态变量和非静态变量的区别 概念上,所属不同 非静态变量属于对象 静态变量属于类,类变量
内存空间不同,存储位置不同 非静态变量属于对象,所以存放在堆内存中 静态变量属于类,存储在方法区的静态区中
内存时间不同,生命周期不同 非静态变量属于对象,所以生命周期和对象相同,随着对象的创建而存在,随着对象的消失而消失。 静态变量属于类,所以生命周期和类相同,随着类的加载(创建对象、类名访问静态变量、类名访问静态方法、反射的方式、加载子类、运行某个测试类)而存在,随着类的消失(内存管理)而消失
访问方式不同 非静态变量只能使用对象名访问 静态变量既可以通过对象访问,也可以通过类名访问。
当static 修饰成员方法时,该方法称为类方法或静态方法。静态方法在声明中有static ,建议使用类名来直接调用,而不需要创建类的对象。调用方式非常简单。
(1)语法格式
修饰符 static 返回值类型 方法名 (参数列表){ // 执行语句 }(2)静态方法调用的注意事项 静态方法可以直接访问静态变量和静态方法。(静态可以访问静态) 静态方法不能直接访问普通成员变量或成员方法。反之,成员方法可以直接访问类变量或静态方法。(静态不能访问非静态) 静态方法中,不能使用this关键字。 (3)调用格式 格式
// 访问类变量 类名.类变量名; // 调用静态方法 类名.静态方法名(参数);static修饰的初始化块 特征:在类加载时,只会执行一次
1.静态方法中不能访问非静态成员变量和成员方法(非静态方法可以访问静态变量) 非静态方法可以访问静态成员变量和静态方法 2.静态方法中不能使用this关键字 3.静态会随着类的加载而加载,随着类的消失而消失,生命周期比对象长 4.有与对象而存在。—>静态先存在,对象后存在。 5.被所有实例(对象)共享 6.可以直接被类名调用
静态变量(类变量)和实例变量的区别 存放位置 类变量随着类的加载而存在于方法区中。 实例变量随着对象的建立而存在于堆内存中。
生命周期 类变量生命周期最长,随着类的消失而消失 实例变量的生命周期随着对象的消失而消失
静态优缺点 优点: 对对象的共享数据进行单独空间的存储,节省空间
缺点: 生命周期过长 访问出现局限性。(静态只能访问静态) 什么时候定义静态变量 当出现需要共享的数据时定义静态变量
单例模式:解决一个类在内存中只能存在一个对象,想要保证对象的唯一。 1 为了避免其他程序过多的建立该类对象。 2 为了其他程序可以访问该类对象,在本类中自定义一个对象。 3 方便其他程序对自定义类的对象的访问,对外提供一些访问方式。
方式: 1在类中创建一个私有的本类对象 2将构造方法私有化 3提供一个用类名调用的公有方法获取该对象。
饿汉式
class Single { private static Single s = new Single(); // 饿汉式 private Single() { } public static Single getInstance() { return s; } }懒汉式
class Single{ private static single s = null;//懒汉式 private Single(){ } public static Single getInstance(){ if(s==null){ s = new Single; } return s; } }1、String就是字符串类型,属于java.lang包,不需要导包 2、所有的字符串常量(“Hello World”、”abc”)都属于String类型的对象 3、字符串字面值属于常量,存储在方法区的常量池中。 4、tring类型在创建之后就无法更改(是一个不可变的字符序列)。 5、不可变的原因是String类型只提供了构造方法,没有提供set方法,因此只能在创建对象的时候,初始化成员变量,将来对象创建完成之后,无法通过方法来修改。
任何好的编程语言的关键目标之一是高效的使用内存,随着应用程序的增长,String字符值占用大量的内存非常常见。对程序而言,全部String字符值中往往有大量的冗余,为了使java更高效地使用内存,JVM留出一块特殊的内存区域,称为“String常量池”。当编译器遇到String字符值时,它检查该池内是否已经存在相同的String字面值。如果找到,则将新的字面值的引用指向现有的String,而不创建任何新的String字面值对象.
1、String():创建一个空字符串 2、String(String original):创建参数字符串的一个副本(参数字符串是在常量池中,构造方法创建的字符串是在堆内存中) 3、String(byte[] arr):将一个字节数组转成一个字符串 将我们不认识的字节数组,转成了我们认识的字符串,过程叫做【解码】 查询的是当前平台默认的编码表 4、String(byte[] arr, int offset, int length):将字节数组的一部分转成字符串 5、String(char[] arr):将字符数组转成字符串 既不是编码,也不是解码,只不过是把字符串成了串 6、String(char[] arr, int offset, int length):将字符数组的一部分转成字符串
(1)API API(Application Programming Interface),应用程序编程接口。 Java API是一本程序员的字典 ,是JDK中提供给我们使用的类的说明文档。
(2)判断功能的方法 1、equals(Object obj): 判断调用者和参数对象描述的字符串内容是否相同 2、equalsIgnoreCase(String otherStr): 忽略大小写判断两个字符串内容是否相同 3、contains(String str): 判断调用者是否包含了str这个子串 4、startsWith(String prefix): 判断调用者是否以prefix开头 5、endsWith(String suffix): 判断调用者是否以suffix结尾 6、isEmpty(): 判断调用者是否是空串
(3)获取功能的放法 1、length(): 获取字符串字符的个数 2、charAt(int index): 返回调用者字符串中索引为index的字符(和length方法结合之后可以遍历字符串) 3、substring(int beginIndex): 获取一个字符串,内容是从当前字符串的beginIndex索引开始 4、substring(int beginIndex, int endIndex): 获取一个指定索引范围的子串 注意事项:1、包含头不包含尾,返回的结果中,不包含endIndex索引指向的字符;2、所有的方法都无法修改字符串对象本身,一般都是返回一个新的字符串对象 5、indexOf家族: indexOf(int ch): 返回ch字符在当前调用者字符串中,第一次出现的索引 indexOf(int ch, int fromIndex): 从fromIndex索引开始寻找,找到ch字符在当前字符串中第一次出现的索引 **indexOf(String str):**返回的是str这个字符串在调用者字符串中第一次出现的索引 indexOf(String str, int fromIndex): 从fromIndex索引开始寻找,找到str字符串在当前字符串中第一次出现的索引(注意:无论从哪个位置开始找,所有字符的索引都不会变化) 6、lastIndexOf家族: 和IndexOf基本一样,只不过是从后往前找,所有字符和字符串的索引也都不会发生变化
(4)转换功能的方法 1、byte[] getBytes(): 将当前字符串,转成字节数组 2、char[] toCharArray(): 将当前的字符串,转成字符数组 3、toUpperCase(): 将当前的字符串,转成全大写形式 4、toLowerCase(): 将当前的字符串,转成全小写形式 5、concat(String str): 将当前调用者,和参数str进行拼接,返回拼接后的长字符串(不常用,因为更多使用的是运算符+) 6、valueOf家族:可以将任意数据类型的数据,转换成字符串
(5)其他方法 1、replace(String oldStr, String newStr): 将调用者中的老串替换成新串 2、trim(): 去掉字符串左右两边的空格、制表符 3、split(): 字符串拆
1、StringBuilder是一个可变的字符序列,因为在类中提供了修改私有成员变量的方法 常用的方法是append和insert,就是在StringBuilder对象本身上,进行修改操作 2、StringBuilder底层和String类型一样,也是维护了一个字符数组,数组是私有的,外界无法直接访问,因此在StringBuilder或者String中对数组进行操作的公有方法的封装
3、String类型和StringBuilder的关系:都是用于描述字符串 (1)、String是不可变的字符序列,没有提供修改私有成员的方法;StringBuilder是可变的字符序列,因为提供了修改成员变量的方法; (2)、String长度本身也不可以变化,StringBuilder长度可以变化,可以认为StringBuilder就像一个可以伸缩的容器,用于存储字符
StringBuilder的构造方法: StringBuilder():创建一个生成器,初始容量为16个字符 StringBuilder(int capacity):创建一个生成器,初始容量为capacity大小 StringBuilder(String str):创建一个生成器,初始值就是str这些字符,初始大小是str+16
获取容积的方法: capacity():获取当前生成器的容器大小 length():获取当前生成器中的字符个数
/* StringBuilder sb = new StringBuilder(); int length = sb.length(); // 获取sb中包含多少个字符 System.out.println(length); int capacity = sb.capacity(); //获取容量 默认 16 System.out.println(capacity); */ StringBuilder sb = new StringBuilder("abc"); int length = sb.length(); // 获取sb中包含多少个字符 System.out.println(length); int capacity = sb.capacity(); //获取容量 这种初始化方式 用字符串的长度+16 System.out.println(capacity);1、append(任意类型):可以将任意数据类型,转成字符,添加到生成器中 2、insert(int index, 任意数据类型):可以将任意数据类型,添加到指定的位置 说明:index的范围是0~当前缓冲区的大小;
StringBuilder sb = new StringBuilder("abc"); sb.append("xyz"); // 追加在末尾 System.out.println(sb); sb.insert(1, "hello"); // 在相应的位置插入 System.out.println(sb);1、deleteCharAt(int index) :删除指定索引的字符 2、delete(int start, int end):删除指定范围的字符,被删除的部分包含头不包含尾
StringBuilder sb = new StringBuilder("abcdefg"); System.out.println(sb); sb.deleteCharAt(1); System.out.println(sb); sb.delete(1,3); // 左闭右开 System.out.println(sb);1、replace(int start, int end ,String str): 将字符串缓冲区中的从start开始到end-1这部分内容,替换成str 2、reverse():将原有字符序列进行反转
StringBuilder sb = new StringBuilder("abcdefg"); //sb.reverse(); //反转 //System.out.println(sb); sb.replace(1, 3, "hello"); //替换 System.out.println(sb);使用String类型拼接字符串:时间和空间上都非常浪费。 使用StringBuilder拼接字符串:时间和空间上都非常节省,无论循环多少次,都只创建两个对象
String转成StringBuilder 1、StringBuilder的构造方法 StringBuilder转成String类型 1、toString的方法 2、使用String的构造方法
相同点: 都是字符串的缓冲区,都是字符串的生成器,都是可变的字符序列
不同点: 1、出现版本不同: StringBuffer在jdk1.0出现的 StringBuilder在jdk1.5出现的 2、线程安全性不同: StringBuffer是线程安全的,在多线程环境下仍然保证数据安全 StringBuilder是线程不安全,在多线程环境下无法保证数据安全 3、效率不同: StringBuffer效率低 StringBuilder效率高
1、String作为方法的参数进行传递,无法修改原值。在被调用的方法中,修改引用指向的对象,和主方法中的引用无关。
2、StringBuilder作为方法的参数进行传递,如果在被调用的方法中,修改的是StringBuilder的引用,那么不会改变原有对象中的数据
3、StringBuilder作为方法的参数进行传递,如果在被调用的方法中,通过该引用修改了对象的数据,那么原值就会发生改变。
1、功能不同 "=="是判断bai两个变量或实例是不是指向同一个内存空间。 "equals"是判断两个变量或实例所指向的内存空间的值是不是相同。
2、定义不同 "equals"在JAVA中是一个方法。 "=="在JAVA中只是一个运算符。
“==”,对于基本类型和引用类型的作用是不同的 基本类型:比较的是值是否相同; 引用类型:比较的是引用是否相同;
重写后的equals()方法用来比较的是两个对象的内容是否相等,如果没有重写的equals()方法,作用等同于“==”
equals方法特点 1、自反性: x.equals(x)返回true; 2、对称性: 若x.equals(y)为true,则y.equals(x)亦为true; 3、传递性: 若x.equals(y)为true且y.equals(z)也为true,则x.equals(z)亦为true; 4、一致性: x.equals(y)的第一次调用为true,那么x.equals(y)的第二次、第三次、第n次调用也均为true,前提条件是没有修改x也没有修改y; 5、对于非空引用x,x.equals(null)永远返回为false。
参考文献: 百度百科-equals 参考文献: equals() 与 == 的区别