例子
public class Test {
public static void main(String[] args) {
//准备数据:创建NewsTitle对象
NewsTitle nt1 = new NewsTitle(1001, "Java中还有这么神奇的事情", "张三");
NewsTitle nt2 = new NewsTitle(1002, "合肥将变成一个没有传销的城市", "李四");
NewsTitle nt3 = new NewsTitle(1003, "合肥比亚迪即将建成开厂", "王五");
NewsTitle nt4 = new NewsTitle(1004, "大湖名城,创新高低", "赵六");
NewsTitle nt5 = new NewsTitle(1005, "大湖名城,创新高低", "孙七");
//准备容器
HashSet hs = new HashSet();
hs.add(nt1);
hs.add(nt2);
hs.add(nt3);
hs.add(nt4);
hs.add(nt5);
hs.add(nt1);
hs.add(nt1);
System.out.println(hs.size());//5 因为他唯一,当重复了就不再往里加了
for (Object object : hs) { //因为set是无序的,所以每一次遍历都会输出的顺序不同(不考虑内存缓存问题)
System.out.println(object);
}
System.out.println("-------------------");
//set集合是无序的,所以不能使用get(下标)获取元素
//hs.get(0);
Iterator it = hs.iterator();
while(it.hasNext()){
Object obj =it.next();
NewsTitle nt = (NewsTitle)obj;
System.out.println(nt);
}
}
}
特例
public class Demo {
public static void main(String[] args) {
Set set = new HashSet();
String s1 = new String("java");
String s2 = s1;
String s3 = new String("JAVA");
NewsTitle nt1 = new NewsTitle(1001, "Java中还有这么神奇的事情", "张三");
NewsTitle nt2 = new NewsTitle(1001, "Java中还有这么神奇的事情", "张三");
set.add(nt1);
set.add(nt2);
System.out.println(set.size());//2 //new了两个不同的对象,回头搞一下String类和普通类 堆内存和栈内存存放方式
set.add(s1);
set.add(s2);
set.add(s3);
System.out.println(set.size());//4
}
}
3.HashMap
例子
public class Test {
/*
* 需求说明
* 学员应聘至外企工作,每个学员都会有一个英文名称,对应该学员对象。
* 请实现通过英文名称,获得该学员对象的详细信息
* 学员属性包括姓名以及性别
*/
public static void main(String[] args) {
//创建学生对象
Student stu1 = new Student("张三", "男"); //已经重写了toString()方法
Student stu2 = new Student("李四", "男");
Student stu3 = new Student("如花", "女");
//创建HashMap集合对象
HashMap hm = new HashMap();
//将学生对象添加到集合中
hm.put("jack", stu1);
hm.put("tom", stu2);
hm.put("rose", stu3);
Object obj = hm.get("jack");
Student stu = (Student)obj;
System.out.println("Jack对应的学员信息为:姓名:"+stu.getName()+",性别:"+stu.getGender());
System.out.println("--------------------------");
//使用键值对的方式遍历输出所有学员的姓名和性别
Set set =hm.entrySet();
for(Object object:set){
Map.Entry me = (Map.Entry)object;
//获取键值对的键
Object obj1 = me.getKey();
String key = (String)obj1;
//获取键值对的值
Object obj2=me.getValue();
Student student = (Student)obj2;
System.out.println(key+"对应的学员姓名:"+student.getName()+",性别为:"+student.getGender());
}
}
}
使用键值对方式遍历输出
Set set = (new HashMap).entrySet();
for(Object obj : set){
Map.Entry me =(Map.Entry)obj;
Object obj1 =me.getKey(); //获取键值对的健(重写toString()方法,可以直接输出obj1)
Object obj2 =me.getValue(); //获取键值对的值
}
例子
public class Test {
/*
* 需求说明
* 学员应聘至外企工作,每个学员都会有一个英文名称,对应该学员对象。
* 请实现通过英文名称,获得该学员对象的详细信息
* 学员属性包括姓名以及性别
*/
public static void main(String[] args) {
//创建学生对象
Student stu1 = new Student("张三", "男");
Student stu2 = new Student("李四", "男");
Student stu3 = new Student("如花", "女");
//创建HashMap集合对象
HashMap hm = new HashMap();
//将学生对象添加到集合中
hm.put("jack", stu1);
hm.put("tom", stu2);
hm.put("rose", stu3);
Object obj = hm.get("jack");
Student stu = (Student)obj;
System.out.println("Jack对应的学员信息为:姓名:"+stu.getName()+",性别:"+stu.getGender());
System.out.println("--------------------------");
//使用键值对的方式遍历输出所有学员的姓名和性别
Set set =hm.entrySet();
for(Object object:set){
Map.Entry me = (Map.Entry)object;
//获取键值对的键
Object obj1 = me.getKey();
String key = (String)obj1;
//获取键值对的值
Object obj2=me.getValue();
Student student = (Student)obj2;
System.out.println(key+"对应的学员姓名:"+student.getName()+",性别为:"+student.getGender());
}
}
}
3.1 HashMap常用方法(加上泛型)
public V put(K key, V value){}
public V remove(Object key) {}
public int size() {}
public boolean containsKey(Object key) {}
在HashMap集合中,键值对的健若是有,则返回true
public boolean containsValue(Object value) {}
在HashMap集合中,键值对的值若是有,则返回true
public Collection<V> values() {}
返回的是获取值的集合
public Set<K> keySet() {} 返回的是键值对的集合
public Set<Map.Entry<K,V>> entrySet() {} 返回的是将集合中的键值对全部取出来存储到Set集合(我觉得是把引用赋值给Set集合),目的是为了下一步可以调用iterator()方法,因为是在HashMap内部的类实现了iterator方法,HashMap没有办法直接调用这个方法
返回的是获取的是键值对的健的集合(可以直接进行打印,打印出的是健的集合)
这里需要注意一点,那么要分别打印呢?(需要进源码看一下....)
step overF6 不进入内部,只执行自己写的代码
step overF5 进入内部,执行所有需要执行的代码
(HashMap类里面有一个内部类KeySet,而KeySet有继承了AbstractSet)
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable
{
............
private final class KeySet extends AbstractSet<K> {
public Iterator<K> iterator() {
return newKeyIterator();
}
.........
}
}
(Abstract类实现了Set接口,所以重写了Set接口中的iterator()方法,但这个抽象类没有重写iterrator()方法,又被HashMap<K,V>继承了,所以是HashMap类实现了Set接口中的iterator()方法)
public abstract class AbstractSet<E> extends AbstractCollection<E> implements Set<E> {
}
阿西吧..........
看下面的例子,就是为了看懂下面两行代码
Set<String> keys2 = hm.keySet();
Iterator<String> it = keys2.iterator(); //疑惑就在为什么Set类型的接口可以调用iterator,原因就是HashMap绕了一圈实现了Set接口
例子
public class Test {
public static void main(String[] args) {
//准备键值对容器用来存储键值对
HashMap<String,String> hm = new HashMap<String,String>();
//向集合中存储数据
hm.put("CN", "中华人民共和国");
hm.put("RU","俄罗斯联邦");
hm.put("US", "美利坚合众国");
hm.put("JP", "日本");
System.out.println(hm.size());
String str1 =hm.get("CN");
System.out.println(str1);
//Object remove(key):根据键来删除键值对,返回值是键对应的值
String str2=hm.remove("JP");
System.out.println(str2);
System.out.println(hm.size());
System.out.println(hm.containsKey("CN"));//true
System.out.println(hm.containsKey("JP"));//false
System.out.println(hm.containsValue("中华人民共和国"));//true
//keySet():返回集合中所有键值对的键的集合
Set<String> keys=hm.keySet();
for (String object : keys) {
String key = object;
String obj =hm.get(key);
String value = obj;
System.out.println(key+"---"+value);
}
System.out.println("--------------------");
//Collection values():获取值得集合
Collection<String> coll = hm.values();
for (String object : coll) {
String value = object;
System.out.println(value);
}
System.out.println("--------------------");
//获取键的集合
Set<String> keys2 = hm.keySet();
Iterator<String> it = keys2.iterator();
while(it.hasNext()){
String key =it.next();
String value =hm.get(key);
System.out.println(key+"---"+value);
}
System.out.println("--------------------");
//使用键值对的方式取出集合中的键值对
Set<Entry<String, String>> keyValues = hm.entrySet(); //将集合中的键值对全部取出来存储到Set集合
Iterator<Entry<String, String>> iterator =keyValues.iterator();//将Set集合中的元素存储到迭代器中
while(iterator.hasNext()){
Entry<String, String> me =iterator.next();//使用next()方法获取迭代器中的元素
String key = me.getKey();//键值对类型对象调用getKey()方法可以获取键值对的键
String value=me.getValue();键值对类型对象调用getValue()方法可以获取键值对的值
System.out.println(key+"~~~~~"+value);
}
}
}
3.2 泛型
将对象的类型作为参数,指定到其它类或者方法上,从而保证类型转换的安全性和稳定性
泛型集合可以约束集合内的元素类型
典型泛型集合ArryList<E>、HashMap<K,V> 对于<E>和<K,V>表示该泛型集合中的元素类型,泛型集合中的数据不再转换为Object
例子
public class Test {
/*
* 需求说明
* 学员应聘至外企工作,每个学员都会有一个英文名称,对应该学员对象。
* 请实现通过英文名称,获得该学员对象的详细信息
* 学员属性包括姓名以及性别
*/
public static void main(String[] args) {
//创建学生对象
Student stu1 = new Student("张三", "男");
Student stu2 = new Student("李四", "男");
Student stu3 = new Student("如花", "女");
//创建HashMap集合对象
HashMap<String,Student> hm = new HashMap<String, Student>();
//将学生对象添加到集合中
hm.put("jack", stu1);
hm.put("tom", stu2);
hm.put("rose", stu3);
Student stu = hm.get("jack");
System.out.println("Jack对应的学员信息为:姓名:"+stu.getName()+",性别:"+stu.getGender());
System.out.println("--------------------------");
Set<Map.Entry<String, Student>> set =hm.entrySet();
//使用迭代器遍历输出所有学员的姓名和性别
Iterator<Entry<String, Student>> iterator= set.iterator();
while(iterator.hasNext()){
Entry<String, Student> me = iterator.next();
System.out.println(me.getKey()+"-------"+me.getValue().getName()+"----------"+me.getValue().getGender());
}
System.out.println("---------------------------");
//使用键值对的方式遍历输出所有学员的姓名和性别
for(Map.Entry<String, Student> me:set){
//获取键值对的键
String key = me.getKey();
//获取键值对的值
Student student=me.getValue();
System.out.println(key+"对应的学员姓名:"+student.getName()+",性别为:"+student.getGender());
}
}
}
3.3 加强for循环
public static void main(String[] args) {
//arr
int arr[]={1,2,3,4,5,6};
for(int i : arr){
System.out.println(i);
}
//string
String s [] = {"hello","world","java"};
for(String i : s){
System.out.println(i);
}
//list
List<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
list.add("java");
for(String i : list){
System.out.println(i);
}
//使用键值对的方式遍历输出所有学员的姓名和性别
HashMap<String,Student> hm = new HashMap<String, Student>();
Student stu1 = new Student("张三", "男");
hm.put("jack", stu1);
Set<Map.Entry<String, Student>> set =hm.entrySet();
for(Map.Entry<String, Student> me:set){
//获取键值对的键
String key = me.getKey();
//获取键值对的值
Student student=me.getValue();
System.out.println(key+"对应的学员姓名:"+student.getName()+",性别为:"+student.getGender());
}
}
Map.Entry<> 查一下资料,了解一下
这些都是集合或者数组的'引用'进行for循环的
3.4 InstanceOf用法
instanceof关键字用于判断一个引用类型变量所指向的对象是否是一个类(或接口、抽象类、父类)的实例。
类型判断关键字。a instanceof b:判断a对象是不是b类型。这儿判断的时候,如果返回此语句已经返回ture,那么把b替换成b的父类型,也会是true
例子
class Animal{
String name;
Animal(String name){
this.name = name;
}
}
public class Dog extends Animal{
Dog(String name){
super(name);
}
public static void main(String[] msg){
Dog gg1 = new Dog("小白");
Animal gg2 = new Animal("旺财");
Animal gg3 = new Dog("狗蛋");
System.out.println(gg1 instanceof Dog); //True本类对象是本类的实例
System.out.println(gg1 instanceof Animal); //True子类对象是父类的实例
System.out.println(gg2 instanceof Dog); //false父类对象不是子类的实例
//System.out.println(Dog instanceof gg2); //编译错误,第一个关键字是引用类型,不可以是类
System.out.println(gg3 instanceof Dog); //True父类引用指向子类对象,该对象仍是子类的实例
}
}
4.枚举
枚举是指由一组固定的常量组成的类型
public enum Genders {
Male,Female
}
(注意下面gender的类型是枚举类型)
public class Student{
private String name;
private Genders gender;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Genders getGender() {
return gender;
}
public void setGender(Genders gender) {
this.gender = gender;
}
}
(注意:stu.setGender(Genders.Male); 该方法里只能传在Gender中已经定义好的)
public class StudentTest {
public static void main(String[] args) {
Student stu = new Student();
stu.setName("张三");
stu.setGender(Genders.Male);
System.out.println(stu.getName()+"--"+stu.getGender());
System.out.println(Math.log10(10));
}
}
5.Java API
5.1 包装类
包装类是把基本数据类型转换为对象,每个基本类型在java.lang包中都有一个相应的包装类
包装类的关系图
包装类的作用
提供了一系列使用的方法
集合不允许存放基本数据类型数据,存放数字时,要用包装类型
包装类的构造方法
所有包装类都可将与之对应的基本数据类型作为参数来构造它们的实例
public Type(type value){ //这是8大类型的构造方法,没有无参构造
this.value = value
}
例如
public Integer(int value) {
this.value = value;
}
除Character类外,其它包装可将一个字符串作为参数构造它们的实例
例如
Integer i = new Integer("123");
注意:
Boolean类型构造方法参数为String类型时,若该字符串内容为true(不考虑大小写),则该Boolean对象表示true,否则表示false
Integer i = new Integer("abc"),这个虽然编译不报错,但是运行时会抛出异常,numberformatexception表示数字格式化异常
Byte b = new Byte(1); 与 Short s = new Short((short) 1);必须要进行强制类型转换,因为,你传过去的是int类型的数据,构造函数接收的是小于int类型的数据
包装类型的常用方法
XXXValue():包装类型转换成基本类型
例子
Integer in = new Integer(25);
int i = in.intValue();
toString():以字符串形式返回包装对象表示的基本类型数据(基本类型->字符串)
例子
String sex = Character.toString('男');
String str = Boolean.toString(true);
Integer inte = new Integer(100);
String str2 = inte.toString();
parseXXX():把字符串转换为相应的基本数据类型数据(Character除外,并且字符串里面的内容要能够转换为数字,否则会报异常)(字符串->基本类型)
byte num2 = Byte.parseByte("123");
System.out.println(num2);
boolean result = Boolean.parseBoolean("TruE");
System.out.println(result);
valueOf():所有包装类都有如下方法(基本类型->包装类) public static Type valueOf(type value)
byte byte2 = 10;
Byte byte3 = Byte.valueOf(byte2);
Byte byte4 = Byte.valueOf((byte)1);
Character cha = Character.valueOf('女');
除Character类外,其他包装类都有如下方法(字符串->包装类)public static Type valueOf(String s)
Byte byte5 = Byte.valueOf("123");
// Character.valueOf("a"); 报错
5.2 Collections与Collection
Collections是一个工具类。工具类是工具,就像Math,Arrays类一样,他是一种工具,集成了很多特定的功能。
比如排序,拷贝,替换,反转等等等功能。工具类不能被实例化。 工具类使用方式:类名.方法名()
总体来说:collection是接口 , collections是工具类
Collections工具类的方法
sort():排序
binarySearch():查找
max()\min():查找最大\最小值
实现一个类的对象之间比较大小,该类要实现Comparable接口,重写compareTo()方法,因为使用sort方法进入内部操作会调用到compartTo方法
************************
由于例子1中String类已经重写过compartTo方法,而例子2中自己定义的类需要自己实现compareTo方法
例子1(String类已经重写过compartTo方法)
public class Demo01 {
public static void main(String[] args) {
ArrayList<String> al = new ArrayList<String>();
al.add("wseurfhu");
al.add("dsfsdf");
al.add("asdewre");
al.add("sdfsf");
al.add("afhth");
System.out.println("集合排序之前:");
for (String string : al) {
System.out.println(string);
}
//Collections.sort():对集合进行排序
Collections.sort(al);
System.out.println("集合排序后:");
for (String string : al) {
System.out.println(string);
}
//int binarySearch(集合名,查找的数据):查找元素,返回查找元素所在的下标,如果查找不到元素,返回一个负值。 注意:使用该方法之前,对先对集合进行升序排序,否则不能保证查询结果的正确性
int index = Collections.binarySearch(al, "sdfsfgj");
System.out.println(index);
//max()/min():求集合中的最大值最小值
String max = Collections.max(al);
System.out.println(max);
String min = Collections.min(al);
System.out.println(min);
Collections.reverse(al);
System.out.println("集合元素反转之后:");
Iterator<String> it=al.iterator();
while(it.hasNext()){
String str = it.next();
System.out.println(str);
}
}
}
例子2 (实现Comparable接口)
public class Student implements Comparable{
private int number=0; //学号
private String name=""; //学生姓名
private String gender=""; //性别
public int getNumber(){
return number;
}
public void setNumber(int number){
this.number=number;
}
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public String getGender(){
return gender;
}
public void setGender(String gender){
this.gender=gender;
}
public int compareTo(Object obj){
Student student=(Student)obj;
if(this.number==student.number){
return 0; //如果学号相同,那么两者就是相等的
}else if(this.number>student.getNumber()){
return 1; //如果这个学生的学号大于传入学生的学号
}else{
return -1; //如果这个学生的学号小于传入学生的学号
}
}
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
public class Test {
public static void main(String[] args) {
Student student1=new Student();
student1.setNumber(5);
Student student2=new Student();
student2.setNumber(2);
Student student3=new Student();
student3.setNumber(1);
Student student4=new Student();
student4.setNumber(4);
ArrayList<Student> list=new ArrayList<Student>();
list.add(student1);
list.add(student2);
list.add(student3);
list.add(student4);
System.out.println("-------排序前-------");
Iterator<Student> iterator=list.iterator();
while(iterator.hasNext()){
Student stu=iterator.next();
System.out.println(stu.getNumber());
}
//使用Collections的sort方法对list进行排序
System.out.println("-------排序后-------");
Collections.sort(list);
iterator=list.iterator();
while(iterator.hasNext()){
Student stu=iterator.next();
System.out.println(stu.getNumber());
}
}
}
public boolean nextBoolean() {...}
每次运行随机生成true或者false
public int nextInt() {}
不带参数的nextInt()会生成所有有效的整数(包含正数,负数,0)
public int nextInt(int n) {}
带参的nextInt(int x)则会生成一个范围在0~x(不包含X)内的任意正整数
例子
Random random1 = new Random();
System.out.println(random1); //java.util.Random@7910769b
boolean result1 = random1.nextBoolean(); //每次运行随机生成true或者false
System.out.println(result1);
int result2= random1.nextInt(); //随机生成int区间内的数
System.out.println(result2);
int result3 = random1.nextInt(10); //随机生成一个0到10之间的数,包括0,但不包括10
System.out.println(result3);
Random random2 = new Random(1);
System.out.println(random2.nextInt());
System.out.println(random2.nextInt(100));
Random random3 = new Random(10L);
System.out.println(random3.nextInt());
注意
当传入了一个种子数时,那么它调用方法的时候,答案就是固定的了,例如,当种子数为1时,它的nextInt()方法返回值永远是-1155869325,它的 nextInt(100)返回值永远是88
6.3 String类常用方法
先来点开胃小菜
System.out.println(10+20+"hello");
System.out.println(10+"hello"+20);
System.out.println("hello"+10+20); //hello先和10进行字符串拼接(从左往右运算)
System.out.println("hello"+(10+20));
答案
30hello
10hello20
hello1020
hello30
------------------------------------------------------
public int length()
public int indexOf(int ch)
public int lastIndexOf(String str)
public String substring(int beginIndex)
public String substring(int beginIndex, int endIndex)
public String trim()
public String[] split(String regex)
public char charAt(int index)
public boolean endsWith(String suffix)
public byte[] getBytes()
public String toLowerCase()
public String toUpperCase()
public String concat(String str)
例子1
public static void main(String[] args) {
//public int indexOf(int ch) 传的是ASCII码值,搜索第一个出现的字符ch(或字符串value),如果没有找到,返回-1
//public int indexOf(String value) 搜索第一个出现的字符ch(或字符串value),如果没有找到,返回-1
//常用ASCII码值 A:65 a:97 0:48
String str = "abcAbabkmn";
int num = str.indexOf(65);
System.out.println(num); //3
System.out.println(str.indexOf("a")); //0
//public int lastiIndexOf(int ch) 传的是ASCII码值,搜索最后一个出现的字符ch(或字符串value),如果没有找到,返回-1
//public int lastIndexOf(String value) 搜索最后出现的字符ch(或字符串value),如果没有找到,返回-1
System.out.println(str.lastIndexOf("a")); //5
//public String substring(int index)提取从位置索引开始的字符串部分
String newStr =str.substring(3);
System.out.println(str); //abcAbabkmn
System.out.println(newStr); //Ababkmn
// public String substring(int beginindex, int
// endindex):提取beginindex和endindex之间的字符串部分,包括开始索引的字符,不包括结束索引的字符
String newStr2 = str.substring(2, 4);
System.out.println(str); //abcAbabkmn
System.out.println(newStr2); //cA
// public String trim():返回一个前后不含任何空格的调用字符串的副本
String str3 = " abc qwert ";
String newStr3 = str3.trim();
System.out.println(str3); // abc qwert
System.out.println(newStr3); //abc qwert
System.out.println("-----------------");
// String[] split(String regex) :根据拆分规则对字符串进行拆分
String song = "长亭外,古道边,芳草碧连天,晚风拂,柳笛声残,夕阳山外山";
String[] strs = song.split(",");
for (String string : strs) {
System.out.println(string);
}
// 我爱你你不爱我但是我很爱你可我就是不爱你
String love = "我爱你你不爱我但是我很爱你可我就是不爱你";
String[] loves = love.split("爱");
for (String string : loves) {
System.out.println(string);
}
System.out.println("--------------");
char ch = love.charAt(1);
System.out.println(ch); //爱
boolean result = love.endsWith("我就是不爱你"); //根据字符串的结尾语句,判断是否相同
System.out.println(result); //true
System.out.println("--------------");
String love1 = "ABCDEFGHI"; //考虑到编码问题,所以不使用汉字
byte[] bytes = love1.getBytes(); //把字符串变成byte型数组
for (int i = 0; i < bytes.length; i++) {
System.out.print(bytes[i]+"--"+(char)bytes[i]+"\t"); //65--A 66--B 67--C 68--D 69--E 70--F 71--G 72--H 73--I
}
//toLowerCase()方法:将大写英文字母转换为小写
//toUpperCase()方法:将小写英文字母转换为大写
String str3 = "AbcdE";
System.out.println(str3.toLowerCase()); //abcde
System.out.println(str3.toUpperCase()); //ABCDE
//字符串的连接: + concat()
String str5 = "大湖名称";
String str6 = "创新高地";
System.out.println(str5+str6); //大湖名称创新高地
String result = str5.concat(str6);
System.out.println(result); //大湖名称创新高地
}
例子2
//输入一行字符,分别统计出其中英文字母、空格、数字和其它字
public class Demo01 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
int lat=0,spa=0,num=0,oth=0;
for(int i=0;i<str.length();i++) {
if(str.charAt(i)>127){ //汉字都是大于127的
System.out.println("*");
}
else if(str.charAt(i)==' ') {
spa++;
}
else if((str.charAt(i)>=65&&str.charAt(i)<=90)||(str.charAt(i)>=97&&str.charAt(i)<=122)) { //65--90 97--122
lat++;
}
else if(str.charAt(i)>=48&&str.charAt(i)<=57) { // 数0 到10的ASCII表 48--57
num++;
}
}
oth = str.length()-num-spa-lat;
System.out.println("字母个数:"+lat+"\n数字个数:"+num+"\n空格个数:"+spa+"\n其他字符个数:"+oth);
}
}
6.4 StringBuffer类常用方法
我们如果对字符串进行拼接操作,每次拼接,都会构建一个新的String对象,既耗时,又浪费空间。而StringBuffer就可以解决这个问题。
StringBuffer与String都是final,不可被继承。
StrinBuffer的操作都是在原有的基础上进行操作,不复制另一份
public StringBuffer append(String str) //添加字符串str,返回字符缓冲区
public StringBuffer insert(int offset, String str) //向任意位置,添加字符串str,返回字符缓冲区
public synchronized String toString()
public synchronized StringBuffer replace(int start, int end, String str)
例子
public static void main(String[] args) {
//将一个数字字符串转换成逗号分隔的数字串,即从右边开始每三个数字由逗号分隔
//第一步:获取键盘输入的数字
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个串数字");
String num = sc.next();
System.out.println("---------------");
//第二部:一会要使用StringBuffer里的insert()方法,所以先要转换成StringBuffer
StringBuffer sb = new StringBuffer(num);
System.out.println(sb); //12345678
//向字符串中插入,从后面开始插入,也就是说要反着来插入
for(int i=sb.length()-3;i>0;i-=3){
sb.insert(i,",");
}
System.out.println(sb); //12,345,678
StringBuffer sb1 = new StringBuffer("我喜欢你");
StringBuffer sb2 = sb1.append("问世间情为何物,直教人生死相许");
System.out.println(sb1); //我喜欢你问世间情为何物,直教人生死相许
System.out.println(sb2); //我喜欢你问世间情为何物,直教人生死相许
StringBuffer sb3 = new StringBuffer("我喜欢你,b,是吧bb3");
StringBuffer sb4 = sb3.replace(5,8,"爱"); //会把[5,8)去掉,换成爱 (从0开始数)
System.out.println(sb4); //我喜欢你,爱吧bb3
}
7.日期类
7.1 Date类
常用方法
public int getYear() //需要加上1900
public int getDay() //星期日是0,星期六是6
例子
public static void main(String[] args) {
Date date =new Date();
//一般来说只有重写toString()方法,输出类的引用才不会输出地址
System.out.println(date); //Sat Jul 02 10:03:49 CST 2022
Demo01 d =new Demo01();
// 对于引用类型在println输出,这个引用类型都会调用到toString()方法,Object中的toString()方法返回的值 getClass().getName() + "@" + Integer.toHexString(hashCode());
System.out.println(d);//cn.bdqn.demo02.Demo01@5ba51364
System.out.println(d.getClass().getName()); // cn.bdqn.demo02.Demo01
int year = date.getYear()+1900;
System.out.println(year);
int day = date.getDay();
System.out.println(day);
switch (day) {
case 0:
System.out.println("星期日");
break;
case 6:
System.out.println("星期六");
break;
}
}
7.2 SimpleDateFormat类
public final String format(Date date)
例子
Date date =new Date();
System.out.println(date);
SimpleDateFormat sdf = new SimpleDateFormat();
System.out.println(sdf); //java.text.SimpleDateFormat@b5341f2a
String str =sdf.format(date);
System.out.println(str); //22-7-2 上午11:00
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str1 =sdf1.format(date);
System.out.println(str1); //2022-07-02 11:02:59
7.3 Calendar类
public int get(int field)
例子
public static void main(String[] args) {
// 通过查询API知道Calendar类是一个抽象类,不能直接实例化,
// 可以调用Calendar类中的getInstance() 方法获得getInstance() 方法获得Calendar类的引用
Calendar cal = Calendar.getInstance();
System.out.println(cal);
// 输出上面的cal的可以得到很多的数据,比如年月日时分秒星期数等,但是形式不是我们想要的,所以我们要进行转换
// 获取年
int year = cal.get(Calendar.YEAR);
System.out.println(year); //2022
// 获取月份
int month = cal.get(Calendar.MONTH);// 在日历cal中第一个月用0表示,第二个月用1表示,以此类推
System.out.println(month + 1); //7
// 获取日
int day = cal.get(Calendar.DAY_OF_MONTH);
System.out.println(day); //2
// 获取时分秒
int hour = cal.get(Calendar.HOUR);
int minute = cal.get(Calendar.MINUTE);
int second = cal.get(Calendar.SECOND);
System.out.println(hour+":"+minute+":"+second); //11:56:6
//获取今天是这一年的第多少天
int dayYear=cal.get(Calendar.DAY_OF_YEAR);
System.out.println("今天是这一年的第"+dayYear+"天"); //今天是这一年的第183天
//获取星期
int dayWeek =cal.get(Calendar.DAY_OF_WEEK);
System.out.println(dayWeek-1); //6
}
继承Thread类实例
public class Test {
public static void main(String[] args) {
//创建线程类对象
MyThread mt1 = new MyThread("天山童姥");
MyThread mt2 = new MyThread("逍遥子");
// start()方法是启动线程的方法
mt1.start();
mt2.start();
//当同时启动两个线程以后,会出现两个线程交替占用CPU执行代码的结果
}
}
//一个类要定义成线程类,可以通过继承Thread类来实现,然后重写Thread类的run()方法
public class MyThread extends Thread{
public MyThread(){
}
public MyThread(String name){
super(name);
}
@Override
public void run(){
//在重写的run()方法中编写你要执行的代码,使用循环输出1-20
for(int i=1;i<=20;i++){
System.out.println(Thread.currentThread().getName()+"-"+i);
}
}
}
实现Runnable接口实例
public class Test {
public static void main(String[] args) {
//创建线程类对象
MyRunnable mt1 = new MyRunnable();
Thread thread1 = new Thread(mt1,"千里眼");
Thread thread2 = new Thread(mt1);
thread1.start();
thread2.start();
//start()方法是Thread类中的方法,而我们需要通过start()放啊来调用run()方法,不能直接调用run()方法
//但是Runnable接口中只有一个抽象方法run()方法,那么实现Runnable接口的子类不能调用start()方法
//解决办法
//将实现Runnable接口的类对象作为参数传递给Thread构造方法,然后通过Thread类对象调用start()方法
}
}
9.2 锁机制
/**
* 使用同步代码块的方式解决取款问题
* Account类:银行账户类
*/publicclassAccount{privateint balance =500;//余额publicintgetBalance(){return balance;}//取款publicvoidwithdraw(int amount){
balance = balance-amount;}}//TestAccount类:取款的线程类 publicclassTestAccountimplementsRunnable{// 所有用TestAccount对象创建的线程共享同一个账户对象privateAccount acct =newAccount();publicvoidrun(){for(int i =0; i <5; i++){makeWithDrawal(100);// 每次取款100元if(acct.getBalance()<0){System.out.println("账户透支了!");}}}// 取款privatevoidmakeWithDrawal(int amt){synchronized(acct){// 同步查询和取款的代码块if(acct.getBalance()>= amt){// 如果余额大于100,则足够,可以取款System.out.println(Thread.currentThread().getName()+"准备取款");try{Thread.sleep(500);// 0.5秒后实现取款}catch(InterruptedException e){
e.printStackTrace();}
acct.withdraw(amt);System.out.println(Thread.currentThread().getName()+"完成取款");}else{// 余额不足给出提示System.out.println("余额不足支付"+Thread.currentThread().getName()+"的取款,余额为"+ acct.getBalance());}}}}//测试类publicclassTest{publicstaticvoidmain(String[] args){// 创建两个线程TestAccount r =newTestAccount();Thread one =newThread(r);Thread two =newThread(r);
one.setName("张三");
two.setName("张三老婆");// 启动线程
one.start();
two.start();}}//使用锁,永远不会出行透支情况
publicclassVolatileOrderTest{staticint a =0, b =0;staticint x =0, y =0;publicstaticvoidmain(String[] args)throwsInterruptedException{for(int i =0;;i++){
i++;
x =0; y =0;
a =0; b =0;Thread one =newThread(newRunnable(){@Overridepublicvoidrun(){try{Thread.sleep(1);}catch(InterruptedException e){
e.printStackTrace();}
a = y;
x =1;}});Thread two =newThread(newRunnable(){@Overridepublicvoidrun(){try{Thread.sleep(1);}catch(InterruptedException e){
e.printStackTrace();}
b = x;
y =1;}});
one.start();
two.start();
one.join();
two.join();System.out.println("第"+ i +"次 a="+ a +" b="+ b);if(a==1&& b==1)break;}}}
指令重排的前提
是不是所有的代码都可能发生指令重排呢?当然不是的,只有满足一定的条件,符合一些规则才会发生。
as-if-serial
as-if-serial语义的意思是:不管怎么重排序,单线程程序的执行结果不能被改变。编译器、runtime和处理器都必须遵守as-if-serial语义。
为了遵守as-if-serial语义,编译器和处理器不会对存在数据依赖关系的操作做重排序,因为这种重排序会改变执行结果。但是,如果操作之间不存在数据依赖关系,这些操作就可能被编译器和处理器重排序。
int i = 0;
int j = i + 1; //下面这条语句就依赖上面的语句,不会发生指令重排