String是java.lang 包下的不需要导包
通过new 创建的字符串对象,每次new都会申请一个内存空间,虽然内容相同但是地址不同。
通过""创建的字符串,JVM只会建立一个String对象,并在字符串常量池中维护
例:
常规字符串拼接操作,每次拼接都会构建一个新的String对象,耗时且浪费内存空间。所以引入StringBuilder解决这个问题
String:内容不可变
StringBuilder 可看作一个容器,对象中的内容是可变的
Arrays 工具类,包含操作数组的各种方法
工具类,构造方法用private修饰(API里没有构造方法).成员用public static修饰
封装基本数据类型,提供更多功能操作该数据,如基本数据类型和字符串之间的转换
除Integer--int; Character--char外,其他类型的包装类,都对应首字母大写即可
package collection;
public class IntegerDemo {
public static void main(String[] args) {
//int---String
int number = 100;
//方式1,字符串拼接
String s1 = ""+number;
System.out.println(s1);
//方式2.
//public static String valueOf(int i) 返回int参数对应的字符串
String s2 = String.valueOf(100);
System.out.println(s2);
System.out.println("=================");
//String--- int
//方式1 String---Integer--int
String s = "100";
Integer i = Integer.valueOf(s);
int i1 = i.intValue();
System.out.println(i1);
//方式2 String---int
// parseInt(String s)
int i2 = Integer.parseInt(s);
System.out.println(i2);
}
}
例2
package collection;
import java.util.Arrays;
/*
需求:
有一个字符串"91 27 46 38 50",请写程序最终输出“27 38 46 50 91”
思路:
1.定义一个字符串
2. 把字符串中的数字存储到一个int类型的数组中
split 分割成String[]数组
parseInt 转化字符串为int型数组
3. 对int型数组排序
4. 排序后数组使用StringBuilder来拼接成字符串
5. 输出结果
*/
public class IntegerTest {
public static void main(String[] args) {
String s ="91 27 46 38 50";
String[] strArray = s.split(" ");
/* for (int i = 0; i < strArray.length; i++) {
System.out.println(strArray[i]);
}*/
int[] arr = new int[strArray.length];
for (int i = 0; i < arr.length; i++) {
arr[i] = Integer.parseInt(strArray[i]);
}
/* for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}*/
Arrays.sort(arr);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
if(i == arr.length-1){
sb.append(arr[i]);
}else{
sb.append(arr[i]).append(" ");
}
}
String s1 = sb.toString();
System.out.println("result:"+ s1);
}
}
Integer iii = null;
if(iii!=null){
iii +=300; //NullPointException
}
在开发中使用引用变量/对象之前(含包装类对象),最好先做不为null的判断
Java.util.Date表示一个特定的时间,精确到毫秒
用于格式化日期和解析日期
Date d = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
sdf.format(d)
String ss = "2048-08-09 11:11:11";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date dd = sdf2.parse(ss);
提供某一时刻和日历字段之间转换方法
常用方法:
Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH)+1;
int day = c.get(Calendar.DATE);
System.out.println(year + " year " + month+" month "+ day+" day");
c.add(Calendar.YEAR, 10);
c.add(Calendar.DATE, -5);
year = c.get(Calendar.YEAR);
month = c.get(Calendar.MONTH)+1;
day = c.get(Calendar.DATE);
System.out.println(year + " year " + month+" month "+ day+" day");
c.set(2048, 11, 11);
c.add(Calendar.DATE, -5);
year = c.get(Calendar.YEAR);
month = c.get(Calendar.MONTH)+1;
day = c.get(Calendar.DATE);
System.out.println(year + " year " + month+" month "+ day+" day");
结果:
2021 year 4 month 8 day
2031 year 4 month 3 day
2048 year 12 month 6 day
例 输出2月份有多少天(借助Calendar不用手动判断是否闰年)
/*
需求:获取任意一年的二月有多少天
思路:
3月减一天就是2月的最后一天,也就输出了二月有多少天
1.键盘录入任意月份
2. 设置日历对象的年月日
年:来自键盘录入
月:设置为2即为3月
日:设置为1
3. 往前推一天,并输出
*/
public class CalendarDemo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int year = sc.nextInt();
int month = 2;
int day =1;
Calendar calendar = Calendar.getInstance();
calendar.set(year,month,day);
calendar.add(Calendar.DATE,-1);
System.out.println(calendar.get(Calendar.DATE));
}
包含静态字段和方法,不能被实例化
常用方法
基本数值类型工具类
常用方法
存储多个数据,且长度不固定,原有的数组不能满足需求,引入集合的概念
集合特点:可变存储空间,容量可以发生改变
ArrayList
Iterator:迭代器,集合专用遍历方式
public static void main(String[] args) {
//创建集合对像
Collection<String> c = new ArrayList<String>();
//创建元素,有时元素/对象不是简单的字符串,需要显示创建步骤
String s1 = "hello";
String s2 = "world";
String s3 = "java";
//添加元素到集合
c.add(s1);
c.add(s2);
c.add(s3);
//遍历集合
//获取迭代器
Iterator <String> iterator = c.iterator();
//通过迭代器判断是否为空,空还去使用会报NoSuchElementException,所以要提前判断
while(iterator.hasNext()){
//获取下一个元素
String s = iterator.next();
System.out.println(s);
}
}
在子类ArrayList学过,注意操作时要保证索引是存在的
add(int index,E Element),E remove(int index), E set(int index, E element), E get (int index)
例:遍历List集合可以用迭代器,因为其是序列还可用for循环遍历,判断条件是size的大小
for(int i =0; i<list.size();i++){
String s = list.get(i);
System.out.println(s);
}
package collections;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/*
* 需求:遍历集合,如果集合中有world元素,就添加一个"javaee" 元素
*/
public class ListDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
list.add("happy");
Iterator<String> it = list.iterator();
boolean flag = false;
while(it.hasNext()){
String s = it.next();
if("world".equals(s)){
list.add("javaee");
}
}
System.out.println(list);
}
}
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
at java.util.ArrayList$Itr.next(ArrayList.java:791)
at collections.ListDemo.main(ListDemo.java:19)
并发修改异常ConcurrentModificationException 继承RuntimeException,是运行期异常
public interface List<E>{
Iterator<E> iterator();
boolean add(E e);
}
public abstract class AbstractList<E> {
// 4. 跟中modCount,发现在父类里定义初始值为0
protected transient int modCount = 0;
}
public class ArrayList<E> extends AbstractList<E> implements List<E>{
//3. 跟踪发现创建迭代器时,实例化了内部类Itr
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
//2. 跟踪expectedModCount在初始化Itr的时候是和modCount相等的
// modCount -- actual modified times
// expectedModCount -- expect modified times
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
// 1. 异常抛出部位,原因modCount和预期的不符
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
public boolean add(E e) {
//5. 跟踪add方法 发现每次add时modCount+1
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
}
for(int i =0; i< list.size();i++){
String s = list.get(i);
if("world".equals(s)){
list.add("javaee");
}
}
List集合特有的迭代器,可以通过listIterator()方法得到
该迭代器允许沿任一方向遍历列表,允许在迭代期间修改列表,并获取列表中迭代器的当前位置
常用方法
为什么ListIterator没有并发问题
在ArrayList的内部类ListItr中add方法如下,最后会把增加的modCount赋值给expectedModCount.
二者始终相等,所以next不会报错
public void add(E e) {
checkForComodification();
try {
int i = cursor;
ArrayList.this.add(i, e);
cursor = i + 1;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
package collection;
import java.util.ArrayList;
import java.util.List;
public class ForDemo {
public static void main(String[] args) {
int [] arr = {1,2,3,4,5};
for(int a: arr){
System.out.println(a);
}
List<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
list.add("java");
for(String s : list){
System.out.println(s);
if(s.equals("world")){
list.add("javaee");
}
}
}
}
输出结果,抛出并发修改异常:
1
2
3
4
5
hello
world
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)
at collection.ForDemo.main(ForDemo.java:16)
Process finished with exit code 1
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("最难");
linkedList.add("不过是");
linkedList.add("坚持");
for (String s : linkedList){
System.out.println(s);
}
Set是个接口,继承Collection, 特点
//HashSet 底层是哈希表,对集合的迭代顺序不做任何保证
public class SetDemo {
public static void main(String[] args) {
Set<String> set = new HashSet<String>();
set.add("hello");
set.add("world");
set.add("java");
//不包含重复元素,已经有hello了,不能再次添加进去
set.add("hello");
//遍历
for(String s: set){
System.out.println(s);
}
}
}
输出:
world
java
hello
哈希值:是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值
Object类中方法 public int hashCode() 返回对象的哈希值
默认情况下,不同对象的hashcode是不同的
hashcode()方法被重写时,可以实现不同对象的哈希值相同。
System.out.println("重地".hashCode()); //1179395
System.out.println("通话".hashCode()); //1179395
String类对hashcode方法进行了重写,所以上述两个汉字字符输出的hashCode一样的
equals比较的是hashCode 和 == 是不一样的。 ==比较的是内存地址, 而hashCode是根据实例变量计算出来的。
Set<String> set = new HashSet<String>();
set.add("hello");
set.add("world");
set.add("java");
------------------------------------------
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
//hash值和元素的hashCode()方法相关
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
//哈希表未初始化,就对其进行初始化
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
//根据对象的哈希值计算出对象的存储位置,如果该位置没有元素就存储元素
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
/*
存入的元素和以前的元素比较哈希值
如果哈希值不同,会继续向下比较,把元素添加到集合
如果哈希值相同,会比较key是否==,或者调用对象的equals()方法比较
如果返回false,会继续向下执行,把元素添加到集合
如果返回的是true,说明元素重复,不存储
*/
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
HashSet集合添加一个元素的过程
HashSet要保证元素的唯一性,需要重写hashCode()和equals()(equal保证内容)方法
package collection;
import java.util.HashSet;
/*
需求:
创建一个存储对象的集合,存储3个学生对象。使用程序实现控制台遍历该集合
思路:
1.定义学生类
2.创建HashSet集合对象
3.创建学生对象
4.把学生添加到集合
5.遍历集合(增强for)
6.重写hashCode和equals方法,Idea自动生成就行
*/
public class HashSetDemo1 {
public static void main(String[] args) {
HashSet<Student> hs = new HashSet<Student>();
Student s1 = new Student("严宽","35");
Student s2 = new Student("陈晓","30");
Student s3 = new Student("何家劲","52");
Student s4 = new Student("何家劲","52");
hs.add(s1);
hs.add(s2);
hs.add(s3);
//重写hashCode和equals方法,不重写就可能添加重复对象
hs.add(s4);
for(Student s : hs){
System.out.println(s);
}
}
}
/////////////////////////////////////////////////////////
package collection;
import java.util.Objects;
public class Student {
private String name;
private String age;
public Student(String name, String age) {
this.name = name;
this.age = age;
}
public Student() {
}
public String getName() {
return name;
}
public String getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name=‘" + name + ‘\‘‘ +
", age=‘" + age + ‘\‘‘ +
‘}‘;
}
@Override
public boolean equals(Object o) {
//引用地址一样,返回true
if (this == o) return true;
//不是同一个类对象,返回false
if (!(o instanceof Student)) return false;
Student student = (Student) o;
//比较两个字段,只有两个字段都相同才返回true
return Objects.equals(getName(), student.getName()) && Objects.equals(getAge(), student.getAge());
}
//hashcode将字段传入Object的hash方法来计算
@Override
public int hashCode() {
return Objects.hash(getName(), getAge());
}
}
package collection;
import java.util.TreeSet;
public class TreeSetDemo {
public static void main(String[] args) {
//集合存储的是引用类型,int元素必须转为使用Integer
TreeSet<Integer> treeSet = new TreeSet<Integer>();
treeSet.add(10);
treeSet.add(8);
treeSet.add(11);
treeSet.add(9);
treeSet.add(10);
for(Object i :treeSet){
System.out.println(i);
}
}
}
package collection;
import java.util.TreeSet;
/*
存储学生对象并遍历,创建集合使用无参构造方法
要求:按照年龄从小岛大排序,年龄相同时,按照姓名的字母顺序排序
*/
public class TreeSetDemo1 {
public static void main(String[] args) {
TreeSet<Student> students = new TreeSet<>();
Student s1 = new Student("xiaoming",22);
Student s2 = new Student("xiaohong",20);
Student s3 = new Student("lanlan",22);
Student s4 = new Student("xiaoming",20);
Student s5 = new Student("xiaoming",20);
students.add(s1);
students.add(s2);
students.add(s3);
students.add(s4);
students.add(s5);
for(Student s : students){
System.out.println(s);
}
}
}
//////////////////////////////
package collection;
import java.util.Objects;
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name=‘" + name + ‘\‘‘ +
", age=‘" + age + ‘\‘‘ +
‘}‘;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Student)) return false;
Student student = (Student) o;
return Objects.equals(getName(), student.getName()) && Objects.equals(getAge(), student.getAge());
}
@Override
public int hashCode() {
return Objects.hash(getName(), getAge());
}
/*
返回是0 认为是相等的不添加
返回是-1 降序,后添加的放在前面
返回是1 升序,后添加的放在后面
可以通过让返回值一直视-1/1/0 测试出来
*/
@Override
public int compareTo(Student o) {
/* 自己写的没有老师写的精妙,int直接相减就可以比较
if(this.age.compareTo(o.age)<0){
return -1;
}
if(this.age.equals(o.age)){
return (this.name.compareTo(o.age));
}
return 1;
*/
int num = this.age-o.age;
//采用三元运算符,只有在年龄相等时才继续比较名字
int num2 = num==0? this.name.compareTo(o.name):num;
return num2;
}
}
输出:
Student{name=‘xiaohong‘, age=‘20‘}
Student{name=‘xiaoming‘, age=‘20‘}
Student{name=‘lanlan‘, age=‘22‘}
Student{name=‘xiaoming‘, age=‘22‘}
package collections;
import java.util.Comparator;
import java.util.TreeSet;
/*
* create TreeSet using constructor with parameter
*/
public class TreeSetDemo {
public static void main(String[] args) {
//在一开始创建TreeSet的时候指定了比较器
//比较器利用匿名内部类实现,直接new Comparator接口
TreeSet<Student> students = new TreeSet<Student>(new Comparator<Student>(){
@Override
public int compare(Student s1, Student s2) {
int num = s1.getAge()-s2.getAge();
int num2 = num == 0? s1.getName().compareTo(s2.getName()):num;
return num2;
}
});
Student s1 = new Student("xiaoming",22);
Student s2 = new Student("xiaohong",20);
Student s3 = new Student("lanlan",22);
Student s4 = new Student("xiaoming",20);
Student s5 = new Student("xiaoming",20);
students.add(s1);
students.add(s2);
students.add(s3);
students.add(s4);
students.add(s5);
for(Student s : students){
System.out.println(s);
}
}
}
///////////////////////////////
package collections;
public class Student {
private String name;
private int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Student() {
super();
// TODO Auto-generated constructor stub
}
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;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
}
例2 成绩排序,按照总分从高到低排序
排序时注意主要条件和次要条件,当主要条件总分相同时,要比较其他科目如语文分数,当科目相同时要比较名字,目的是确保不同人都能添加到集合里
(有重名的用学号解决)
例 3 存储10个0到20间不重复的随机数
分析不重复采用set集合,不需要排序,直接用hashSet
随机数用 Random nextInt(20)+1限制范围
package collections;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
public class TreeSetDemo1 {
public static void main(String[] args) {
Set<Integer> set = new HashSet<Integer>();
//创建随机数生成器
Random r = new Random();
while(set.size()<10){
int number = r.nextInt(20)+1;
set.add(number);
}
for(Integer i: set){
System.out.println(i);
}
}
}
注: 内容是bilibili黑马程序员笔记
原文:https://www.cnblogs.com/drying-net/p/14628522.html