文章目录
一、java 集合
1.1定义:
由若干个确定的元素所构成的整体
在Java中,如果一个Java对象可以在内部持有若干其他Java对象,并对外提供访问接口,我们把这种Java对象称为集合。很显然,Java的数组可以看作是一种集合
String[] ss = new String[10]; // 可以持有10个String对象
ss[0] = "Hello"; // 可以放入String对象
String first = ss[0]; // 可以获取String对象
为什么需要其他集合类?
答:数组有限制:初始化后大小不可变、数组只能按照索引顺序存取,而不同类型的集合类可以变换顺序表的大小,也可以保证无重复数据…
1.2 Collection
- Collection 是java.util包提供的,是除Map外所有其他集合类的根接口。Java的java.util包主要提供了以下三种类型的集合:
- List:一种有序列表的集合,例如,按索引排列的Student的List;
- Set:一种保证没有重复元素的集合,例如,所有无重复名称的Student的Set;
- Map:一种通过键值(key-value)查找的映射表集合,例如,根据Student的name查找对应Student的Map
1.3特点
一是实现了接口和实现类相分离,例如,有序表的接口是List,具体的实现类有ArrayList,LinkedList等
二是支持泛型,我们可以限制在一个集合中只能放入同一种数据类型的元素,例如:
List<String> list = new ArrayList<>(); // 只能放入String类型
-
Java访问集合总是通过统一的方式——迭代器(Iterator)来实现,它最明显的好处在于无需知道集合内部元素是按什么方式存储的。
-
一些不应该继续使用的集合类:
-
Hashtable:一种线程安全的Map实现;
-
Vector:一种线程安全的List实现;
-
Stack:基于Vector实现的LIFO的栈。
不应该被使用的接口: -
Enumeration:已被Iterator取代。
1.4 Set(3)
Map用于存储key-value的映射,对于充当key的对象,是不能重复的,并且,不但需要正确覆写equals()方法,还要正确覆写hashCode()方法。
-
如果我们只需要存储不重复的key,并不需要存储映射的value,那么就可以使用Set。
-
Set用于存储不重复的元素集合,它主要提供以下几个方法:
将元素添加进Set<E>:boolean add(E e)
将元素从Set<E>删除:boolean remove(Object e)
判断是否包含元素:boolean contains(Object e)
Set只存储key,不存储value的Map。经常用于去除重复的元素
要正确的实现equals(),hasCode()方法才能正确的放入Set。
- 最常见的set实现类是HashSet:
public class Hashset<E> implements set<E> {
//持有一个HashMap:
private HashMap<E,object> map = new HashMap<>();
//放入HashMap的value:
private static final object PRESENT = new object();
public boolean add(E e) {
return map.put(e,PRESENT) == null;
}
public boolean contains (object o) {
return map.containsKey(o);
}
public boolean remove(object o) {
return map.remove(o) == PRESENT;
}
}
Set接口并不保证有序,而SortedSet是可以保证有序的
HashSet是无序的,因为它实现了Set接口,并没有实现SortedSet接口;
TreeSet是有序的,因为它实现了SortedSet接口。
HashSet换成TreeSet,在遍历TreeSet时,输出就是有序的,这个顺序是元素的排序顺序:
import java.util.*;
public class Main {
public static void main( string[] args) {
set<string> set = new TreeSet<>();set.add ( "apple" ) ;
set.add ( "banana" );
set.add ( "pear" );
set.add ( "orange" );
for (string s : set) {
system.out. println( s );
}
}
}
使用TreeSet和使用TreeMap的要求一样,添加的元素必须正确实现Comparable接口,如果没有实现Comparable接口,那么创建TreeSet时必须传入一个Comparator对象。
1.5 Map(2)
- Map这种键值(key-value)映射表的数据结构,作用就是能高效通过key快速查找value(元素)。键值对
- 对比List极大程度的提高了通过一个键去查找对应值的效率
例:用Map来实现根据name查询某个Student的代码如下:
import java. util.HashMap;
import java . util.Map ;
public class Main {
public static void main( string[] args) {
Student s = new student( "xiao Ming", 99);
Map<string,Student> map = new HashMap<>( );
map.put( "xiao Ming", s);//将"Xiao Ming"和student 实例映射并关联
Student target = map.get( "xiao Ming" );//通过key查找并返回映射的Student实例
system.out . println(target == s ) ;//true ,同一个实例
system.out. println(target.score) ; //99
student another = map.get ( "Bob" ); //通过另一个key查找
system.out . println( another ) ; //未找到返null
}
}
class student {
public string name ;
public int score;
public student ( string name,int score) {
this.name = name;
this.score = score;
}
}
Map<K, V>是一种键-值映射表,当我们调用put(K key, V value)方法时,就把key和value做了映射并放入Map。当我们调用V get(K key)时,就可以通过key获取到对应的value。如果key不存在,则返回null。和List类似,Map也是一个接口,最常用的实现类是HashMap
- Map中不存在重复的key,因为放入相同的key,只会把原有的key-value对应的value给替换掉。此外,在一个Map中,虽然key不能重复,但value是可以重复的:
Map<String, Integer> map = new HashMap<>();
map.put("apple", 123);
map.put("pear", 123); // ok
1.5.1Map的遍历
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main( string[]args) i
Map<string,Integer> map = new HashMap<>( );
map.put ( "apple", 123);
map.put ( "pear", 456);map.put ( "banana",789) ;
for ( Map.Entry<string,Integer> entry : map.entryset( )) {
String key = entry.getKey( );
Integer value = entry . getValue( );
System. out. println( key + " =" +value);
}
}
}
- Map和List不同的是Map存储的是Ket-Value映射关系,不确保顺序,使用Map时任何依赖顺序的逻辑都是不可靠的。以HashMap为例,假设我们放入"A",“B”,"C"这3个key,遍历的时候,每个key会保证被遍历一次且仅遍历一次,但顺序完全没有保证,甚至对于不同的JDK版本,相同的代码遍历的输出顺序都是不同的!
1.6 List(1)
-
定义:List是最基础的一种集合:是一种有序链表
为数组的升级版本只是不需要连续的空间;List内部按照放入元素的先后顺序存放,每个元素都可以通过索引确定自己的位置,List的索引和数组一样,从0开始。对比数组和List的删除可以发现数组的删除需要把删除位置后的每一个元素依次往前移动添加则是相反,java中的ArrayList也是采用数组来存储的不过他可以改变数组的大小和自动的移动元素来完成增加和删除元素的操作
1.6.1 ArrayList
- size=4拥有4个元素但实际数组大小为5
|A|B|C|D| | - 当添加一个元素到ArrayList时ArrayList自动移动需要移动的元素:
|A|B| |C|D|
|A|B|E|C|D|size=5//size+1 - 若继续添加元素但是数组已经满了ArrayList就会创建一个更大的新数组然后把原来的数组元素复制到新数组并用新数组代替原来的数组:
|A|B|E|C|D| | | | | | | | | | |size=5
ArrayList把添加和删除的操作封装起来,让我们操作List类似于操作数组,却不用关心内部元素如何移动。
List接口主要方法
在末尾添加一个元素:void add(E e)
在指定索引添加一个元素:void add(int index, E e)
删除指定索引的元素:int remove(int index)
删除某个元素:int remove(Object e)
获取指定索引的元素:E get(int index)
获取链表大小(包含元素的个数):int size()
实现List接口不仅可以通过ArrayList实现也可以通过LinkedList通过链表来实
ArrayList和LinkedList比较
我们优先使用ArrayList
1.6.2 List的创建及遍历
- 除了使用ArrayList和LinkedList,我们还可以通过List接口提供的of()方法,根据给定元素快速创建List:
List<Integer> list = List.of(1, 2, 5);
- 但是List.of()方法不接受null值,如果传入null,会抛出NullPointerException异常。
get(int)方法遍历:
import java.util.List;
public class Main {
public static void main(string[] args) {
List<string> list = List.of( "apple", "pear", "banana" );
for (int i=o; i<list.size( ); i++) {
string s = list.get(i);
system.out.println(s);
}
}
}//此方法不推荐代码复杂且只有ArrayList实现get(int)是高效的LinkedList索引越大越慢
推荐使用这个方法:
import java.util.Iterator;
import java.util.List ;
public class Main {
public static void main( string[]args) {
List<string> list = List.of( "apple", "pear", "banana" );
for ( Iterator<string> it = list.iterator ( ); it.hasNext( ); ) {//hasNext()判断是否有下一个元素,
string s = it.next( );//返回下一个元素
system.out.println( s ) ;
}
}
}//Iterator便利List是最高效的方法
下面使用for each循环帮助使用Iterator遍历
import java.util.List;
public class Main {
public static void main( string[]args) {i
List<string> list = List.of ( "apple","pear", "banana" );
for ( string s : list) {
system.out.println( s ) ;
}
}
}//只要实现了Iterable接口的集合类都可以直接用for each循环来遍历
1.6.3 List和Array的转换
- 有三种方法:
1.调用toArray()方法直接返回一个Object[]数组:
import java.util.List;
public class Main {
public static void main(string[] args) {
List<String> list = List.of( "apple","pear", "banana" );
object[] array = list.toArray( );
for ( object s : array) i
system.out.println( s );
}
}
}//用的很少会丢信息类型
2.给toArray(T[])传入一个类型相同的Array,List内部自动把元素复制到传入的Array中:
import java.util.List;
public class Main {
public static void main(string[] args) {
List<Integer> list = List.of(12,34,56);
Integer[] array = list.toArray ( new Integer[3]);//不是泛型参数
for ( Integer n : array) {
system.out.println(n) ;
}
}
}//如过给入类型不匹配的数组会抛出ArrayStoreException
//会自动扩充,恐怖用NULL填充
//Integer[] array = list.toArray(new Integer[list.size()]);//恰好填充完毕
3.通过List接口定义的T[] toArray(IntFunction<T[]> generator)方法:
Integer[] array = list.toArray(Integer[]::new);
4.把Array变为List通过List.of(T…)方法最简单:
Integer[] array = { 1, 2, 3 };
List<Integer> list = List.of(array);
- jdk11之前的Arrays.asList(T…)方法把数组转换成List。
***注意:***返回的List不一定就是ArrayList或者LinkedList,因为List只是一个接口,如果我们调用List.of(),它返回的是一个只读List:
代码:
import java.util.List;
public class Main {
public static void main( string[] args ) i
List<Integer> list = List.of(12,34,56);
list.add (999 ) ; // UnsupportedoperationException对只读调用add(),remove()方法会抛出
}
}
二、常见类
2.1 java Object类
Java Object 类是所有类的父类,也就是说 Java 的所有类都继承了 Object,子类可以使用 Object 的所有方法。
- Object 类位于 java.lang 包中,编译时会自动导入,我们创建一个类时,如果没有明确继承一个父类,那么它就会自动继承
Object,成为 Object 的子类。 - Object 类可以显式继承,也可以隐式继承,以下两种方式是一样的:
public class Runoob extends Object{
//显示继承
}
public class Runoob {
//隐式继承
}
- 类的方法
1 protected Object clone()
//创建并返回一个对象的拷贝
2 boolean equals(Object obj)
//比较两个对象是否相等
3 protected void finalize()
//当 GC (垃圾回收器)确定不存在对该对象的有更多引用时,由对象的垃圾回收器调用此方法。
4 Class<?> getClass()
//获取对象的运行时对象的类
5 int hashCode()
//获取对象的 hash 值
6 void notify()
//唤醒在该对象上等待的某个线程
7 void notifyAll()
//唤醒在该对象上等待的所有线程
8 String toString()
//返回对象的字符串表示形式
9 void wait()
//让当前线程进入等待状态。直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。
10 void wait(long timeout)
//让当前线程处于等待(阻塞)状态,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过参数设置的timeout超时时间。
11 void wait(long timeout, int nanos)
//与 wait(long timeout) 方法类似,多了一个 nanos 参数,这个参数表示额外时间(以纳秒为单位,范围是 0-999999)。 所以超时的时间还需要加上 nanos 纳秒。。
2.2 JAVA String类
-
最简单的方式如下:String str = “Runoob”;
-
用构造函数创建字符串:String str2=new String(“Runoob”);
String 创建的字符串存储在公共池中,而 new 创建的字符串对象在堆上: String s1 = "Runoob"; // String 直接创建 String s2 = "Runoob"; // String 直接创建 String s3 = s1; // 相同引用 String s4 = new String("Runoob"); // String 对象创建 String s5 = new String("Runoob"); // String 对象创建
-
提供一个字符数组参数:
StringDemo.java 文件代码:
public class StringDemo{
public static void main(String args[]){
char[] helloArray = { 'r', 'u', 'n', 'o', 'o', 'b'};
String helloString = new String(helloArray);
System.out.println( helloString );
}
}
用于获取有关对象的信息的方法称为访问器方法。
String 类的一个访问器方法是 length() 方法,它返回字符串对象包含的字符数。
下面的代码执行后,len 变量等于 14:
StringDemo.java 文件代码:
public class StringDemo {
public static void main(String args[]) {
String site = "www.runoob.com";
int len = site.length();
System.out.println( "什么什么 : " + len );
}
}
- String 类提供了连接两个字符串的方法:
string1.concat(string2);
"我的名字是 ".concat("Runoob");
"Hello," + " runoob" + "!"
StringDemo.java 文件代码:
public class StringDemo {
public static void main(String args[]) {
String string1 = "什么什么:";
System.out.println("1、" + string1 + "www.runoob.com");
}
}
String 类使用静态方法 format() 返回一个String 对象而不是 PrintStream 对象。
String 类的静态方法 format() 能用来创建可复用的格式化字符串,而不仅仅是用于一次打印输出。
String fs;
fs = String.format("浮点型变量的值为 " +
"%f, 整型变量的值为 " +
" %d, 字符串变量的值为 " +
" %s", floatVar, intVar, stringVar);
2.3 java StringBuilder类和 java StringBuffer类
- 当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类。和 String
类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。 - StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder
的方法不是线程安全的(不能同步访问)。由于 StringBuilder 相较于 StringBuffer
有速度优势,所以多数情况下建议使用 StringBuilder 类。
public class RunoobTest{
public static void main(String args[]){
StringBuilder sb = new StringBuilder(10);
sb.append("Runoob..");
System.out.println(sb);
sb.append("!");
System.out.println(sb);
sb.insert(8, "Java");
System.out.println(sb);
sb.delete(5,8);
System.out.println(sb);
}
}/*
Runoob..
Runoob..!
Runoob..Java!
RunooJava!
*/
线程安全必须要使用StringBuffer类:
public class Test{
public static void main(String args[]){
StringBuffer sBuffer = new StringBuffer("菜鸟教程官网:");
sBuffer.append("www");
sBuffer.append(".runoob");
sBuffer.append(".com");
System.out.println(sBuffer);
}
}
2.4 java System类
- System 类位于 java.lang 包,代表当前 Java
程序的运行平台,系统级的很多属性和控制方法都放置在该类的内部。由于该类的构造方法是 private
的,所以无法创建该类的对象,也就是无法实例化该类。
System 类有 3 个静态成员变量,分别是 PrintStream out、InputStream in 和 PrintStream err。
1. PrintStream out
System.out.println(data);
2. InputStream in
标准输入流。此流已打开并准备提供输入数据。通常,此流对应于键盘输入或者由主机环境或用户指定的另一个输入源。
3. PrintStream err
标准的错误输出流。其语法与 System.out 类似,不需要提供参数就可输出错误信息。也可以用来输出用户指定的其他信息,包括变量的值。
方法:
- System 类中提供了一些系统级的操作方法,常用的方法有
arraycopy()、currentTimeMillis()、exit()、gc() 和 getProperty()。
- arraycopy() 方法
该方法的作用是数组复制,即从指定源数组中复制一个数组,复制从指定的位置开始,到目标数组的指定位置结束。该方法的具体定义如下:
public static void arraycopy(Object src,int srcPos,Object dest,int destPos,int length)
使用:
public class System_arrayCopy {
public static void main(String[] args) {
char[] srcArray = {'A','B','C','D'};
char[] destArray = {'E','F','G','H'};
System.arraycopy(srcArray,1,destArray,1,2);
System.out.println("源数组:");
for(int i = 0;i < srcArray.length;i++) {
System.out.println(srcArray[i]);
}
System.out.println("目标数组:");
for(int j = 0;j < destArray.length;j++) {
System.out.println(destArray[j]);
}
}
}//将srcArray[1]复制给destArray[1],,,
- currentTimeMillis() 方法
该方法的作用是返回当前的计算机时间,时间的格式为当前计算机时间与 GMT 时间(格林尼治时间)1970 年 1 月 1 日 0 时 0 分 0 秒所差的毫秒数。一般用它来测试程序的执行时间。例如:
long m = System.currentTimeMillis();
- 使用 currentTimeMillis()
方法来显示时间不够直观,但是可以很方便地进行时间计算。例如,计算程序运行需要的时间就可以使用如下的代码:
public class System_currentTimeMillis {
public static void main(String[] args) {
long start = System.currentTimeMillis();
for(int i = 0;i < 100000000;i++) {
int temp = 0;
}
long end = System.currentTimeMillis();
long time = end - start;
System.out.println("程序执行时间" + time + "秒");
}
}//这种方法可以测试不同算法的程序的执行效率高低,也可以用于后期线程控制时的精确延时实现。
- exit() 方法
该方法的作用是终止当前正在运行的 Java 虚拟机,具体的定义格式如下:
public static void exit(int status)
- gc() 方法
该方法的作用是请求系统进行垃圾回收,完成内存中的垃圾清除。至于系统是否立刻回收,取决于系统中垃圾回收算法的实现以及系统执行时的情况。定义如下:
public static void gc()
- getProperty() 方法
该方法的作用是获得系统中属性名为 key 的属性对应的值,具体的定义如下:
public static String getProperty(String key)
public class System_getProperty {
public static void main(String[] args) {
String jversion = System.getProperty("java.version");
String oName = System.getProperty("os.name");
String user = System.getProperty("user.name");
System.out.println("Java 运行时环境版本:"+jversion);
System.out.println("当前操作系统是:"+oName);
System.out.println("当前用户是:"+user);
}
}/*
Java 运行时环境版本:1.8.0_131
当前操作系统是:Windows 10
当前用户是:kks
*/
2.5 java data类
- java.util 包提供了 Date 类来封装当前的日期和时间。 Date 类提供两个构造函数来实例化 Date 对象。
- 第一个构造函数使用当前日期和时间来初始化对象。 Date( )
- 第二个构造函数接收一个参数,该参数是从 1970 年 1 月 1 日起的毫秒数。 Date(long millisec)
获取当前日期时间:
import java.util.Date;
public class DateDemo {
public static void main(String[] args) {
// 初始化 Date 对象
Date date = new Date();
// 使用 toString() 函数显示日期时间
System.out.println(date.toString());
}
}
日期比较:
- Java使用以下三种方法来比较两个日期: 使用 getTime()
方法获取两个日期(自1970年1月1日经历的毫秒数值),然后比较这两个值。 使用方法 before(),after() 和equals()。
例如,一个月的12号比18号早,则 new Date(99, 2, 12).before(new Date (99,2, 18)) 返回true。 使用 compareTo() 方法,它是由 Comparable 接口定义的,Date 类实现了这个接口。
使用 SimpleDateFormat 格式化日期:
import java.util.*;
import java.text.*;
public class DateDemo {
public static void main(String[] args) {
Date dNow = new Date( );
SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd hh:mm:ss");//确定了格式
System.out.println("当前时间为: " + ft.format(dNow));
}
}
使用printf格式化日期:
import java.util.Date;
public class DateDemo {
public static void main(String[] args) {
// 初始化 Date 对象
Date date = new Date(); //c的使用
System.out.printf("全部日期和时间信息:%tc%n",date);
//f的使用
System.out.printf("年-月-日格式:%tF%n",date);
//d的使用
System.out.printf("月/日/年格式:%tD%n",date);
//r的使用
System.out.printf("HH:MM:SS PM格式(12时制):%tr%n",date);
//t的使用
System.out.printf("HH:MM:SS格式(24时制):%tT%n",date);
//R的使用
System.out.printf("HH:MM格式(24时制):%tR",date);
}
}
- 如果要重复提供日期可以利用一个格式化字符串指出要被格式化的参数的索引。索引必须紧跟在%后面,而且必须以$结束。
import java.util.Date;
public class DateDemo {
public static void main(String[] args) {
// 初始化 Date 对象
Date date = new Date();
// 使用toString()显示日期和时间
System.out.printf("%1$s %2$tB %2$td, %2$tY",
"Due date:", date);
}
}