Java学习
数学工具类Math
public static double abs(double num);绝对值
public static double ceil(double num);向上取整
public static double floor(double num);向下取整
public static double round(double num);四舍五入
System.out.println(Math.abs(3.14).14 System.out.println(Math.ceil(3.14).0 System.out.println(Math.floor(3.14).0 System.out.println(Math.round(3.14)
final关键字
1.final修饰类不能继承。
2.final修饰方法无法覆盖。
3.final只能赋值一次修值一次。
4.final一旦修改引用指向某个对象, 不能再指向其他对象,但可以修改引用对象内部的数据。
5.final修改的实例变量必须手动初始化,不能采用系统默认值。
6.final修改的实例变量一般与static联合使用,成为常量。
抽象与接口
1.抽象类定义:在class前添加abstract关键字就行了。
2.抽象类不能实例化,不能创建对象,所以抽象类是用来继承被子类的。
3.final和abstract这两个关键词是对立的,不能联合使用。
4.抽象的子类可以使抽象或非抽象。
5.虽然抽象类不能实例化,但抽象类有结构方法,供子类使用。
6.抽象类中不一定有抽象方法,抽象方法必须出现在抽象类中。
7.如何定义抽象方法?
public abstract void doSome();
8.非抽象类,继承抽象类,必须覆盖抽象类中的抽象方法(实现)。
-
面试题(判断题):Java语言中没有方法的方法都是抽象的。
错了,错了。
Object类种就有很多都没有方法体,都是以“;“结尾的,但是他们都不是抽象方法,例如:
public native int hashCode();
底层调用了这种方法C 写动态链接库程序。
前装饰符列表中没有:abstract。有一个native。表示调用JVM本地程序。
-
接口
1.接口是一种引用数据类型。编译后也是一种class字节码文件。
2.借口完全抽象。
3.如何定义接口:[修饰符列表] interface 接口名{}
4.接口支持多继承。
5.接口只包含常量 抽象方法。
6.接口中的所有元素都是public修饰。(都是公开的。
7.定义界面中的抽象方法:public abstract可以省略修饰符。常量也是。
8.接口中的方法都是抽象的,所以界面中的方法不能有方法体。
//定义接口 interface A{ } ///接口支持继承 interface B extends A{ } 支持多继承 interface C extends A,B{ } ///我的数学方法 interface MyMath{ //常量 public static final double PI = 3.1415926; //也可以省略 double PI = 3.1415926;//PI是常量,不可变 ///抽象方法 public abstract int sum(int a , int b); //也可以省略 //int sum(int a , int b); //接口中的方法可以有方法吗? //错误:界面抽象方法不能带主体 /* void doSome(){ } */ }
1.类与类之间称为继承(关键词:extends),类与接口之间称为实现(关键字:implements)。
2.当一个如果类别实现接口,则必须实现接口中的所有抽象方法(覆盖和重写)。
java类名:interfaceTest
public class interfaceTest { public static void main(String[] args){ //多态 ///引用父类型指向子类型的对象 MyMath mm = new m(); //面向接口编程 int sum = mm.sum(10, 80); int sub = mm.sub(20, 5); System.out.println(sum); System.out.println(sub); } } interface MyMath{ double PI = 3.1415926; int sum(int a , int b);//默认public访问权限 int sub(int a , int b); } ///非抽象类实现接口 class m implements MyMath{ //public不能省略,访问权限不得低于接口。 //实现接口的方法 public int sum(int a , int b){ return a b; } public int sub(int a , int b){ return a-b; } }
多个接口可以同时实现一个类:
弥补了这一机制Java单继承(为简单而出现)带来的缺陷。
public class interfaceTest { public static void main(String[] args){ ///引用父类型指向子类型的对象 A a = new C(); int sum = a.sum(10, 20); //a.sub(20,10); 编译报错,A接口中没有sub()方法 /* *强制转换接口和接口之间没有继承关系,也可以强制转换 但注:操作时可能发生:ClassCastException异常 *编译没有问题,操作有问题 B b = (B) a; a.sub(20,10); **/ //记得在转型前向下转型 if instanceof 进行判断 if(a instanceof B) { B b = (B) a; } System.out.println(sum); //也可以直接向下转型 C c = (C) a; } } interface A{ public int sum(int a , int b); } interface B{ public int sub(int a , int b); } class C implements A{ public int sum(int a, int b) { return a b; } }
equals
import java.util.Objects; public class equalsTest { public static void main(String[] args) { ///多态(自动类型转换) Object o1=new String(); Object o2=new User(); Object o3=new Address(); User u1=new User("张三",new Address("河南","郑州","惠济区")); User u2=new User("张三",new Address("河南","郑州","惠济区")); System.out.println(u1.equals(u2));//true User u3=new User("李四",new Address("河南","郑州","惠济区")); System.out.println(u1.equals(u3));//false } } class User{ String name; Address addr; public User(){ } public User(String name,Address addr){ this.name=name; this.addr=addr; } //equals重写 @Override public boolan equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof User)) return false;
User user = (User) o;
return name.equals(user.name) &&
addr.equals(user.addr);
}
}
class Address{
String zipcode;
String street;
String city;
//无形参
public Address(){
}
//有形参
public Address(String city,String street,String zipcode){
this.city=city;
this.street=street;
this.zipcode=zipcode;
}
//equals重写
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof Address)) return false;
Address address = (Address) o;
return zipcode.equals(address.zipcode) &&
street.equals(address.street) &&
city.equals(address.city);
}
}
数组
数据这种数据结构的优点和缺点是什么?
优点:查询/查找/检索某个下标上的元素时效率极高。可以说是查询效率最高的一个数据结构。
为什么检索效率高?
第一:每一个元素的内存地址在空间储存上是连续的。
第二:每一个元素类型是相同的,所以占用的空间大小一样。
第三:知道每一个元素内存地址,知道每一个元素占用空间的大小,又知道下标,所以通过一个数学表达式就可以计算出某个下标上元素的内存地址。直接通过内存地址定位元素。所以数据的检索效率是高的。
public class arrayTest {
public static void main(String[] args) {
int[] x={1,2,4,3,5};
printArray(x);
//创建String数组
String[] stringArray={"asd","asd","asa","awq"};
printArray(stringArray);
}
private static void printArray(int[] a) {
for (int i = 0; i <a.length ; i++) {
System.out.println(a[i]);//1,2,3,4,5
}
}
public static void printArray(String[] args) {
for (int i = 0; i <args.length ; i++) {
System.out.println("String数组中的元素:"+args[i]);//String数组中的元素:asdString数组中的元素:asdString数组中的元素:asaString数组中的元素:awq
}
}
}
数组的拷贝
public class arrayCopyTest {
public static void main(String[] args) {
int[] src = {1,2,3,4};//创建拷贝源
/* int[] dest = new int[20];//创建拷贝目标
System.arraycopy(src,1,dest,4,3);//调用JDK System类中的arraycopy方法,完成数组的拷贝,注意下标是从0开始
for (int i = 0; i <dest.length ; i++) {
System.out.println(dest[i]);//0 0 0 0 2 3 4...0
}*/
int[] dest = new int[10];
System.arraycopy(src,0,dest,0,src.length);//复制拷贝源数组的全部数据
for (int i = 0; i <dest.length ; i++) {
System.out.println(dest[i]);//1 2 3 4 0 0...
}
Object[] obj = {new Object(),new Object(),new Object()};
Object[] o = new Object[20];
System.arraycopy(obj,0,o,0,obj.length);
for (int i = 0; i < o.length; i++) {
//输出obj对象的地址
System.out.println(o[i]);//java.lang.Object@10f87f48 java.lang.Object@b4c966a java.lang.Object@2f4d3709 null null...
}
}
}
冒泡排序算法
public class mq {
public static void main(String[] args) {
int[]a={1,4,6,2,10,5};
int count=0;
for (int i = a.length-1; i > 0; i--) {
for (int j = 0; j < i; j++) {
//输出次数
count++;
if(a[j]>a[j+1]){
int temp = a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
System.out.println("比较次数:"+count);//比较次数:15
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+" ");//1 2 4 5 6 10
}
}
}
选择排序法
public class select {
public static void main(String[] args) {
int[]a={1,4,6,2,10,5};
for (int i = 0; i < a.length-1; i++) {
int min = i;
for (int j = i+1; j < a.length; j++) {
if(a[j]<a[min]){
min=j;
}
}
if(min!=i){
int temp = a[min];
a[min] = a[i];
a[i] = temp;
}
}
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+" ");//1 2 4 5 6 10
}
}
}
二分法
import java.util.Scanner;
public class ArrayUtil {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int[] a={100,201,300,401,500,600,800,1000};//要求目标序列是拍好序的
System.out.print("元素中有:");
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+" ");
}
System.out.println();//转行
System.out.print("请输入想要查找下标的元素:");
int b = in.nextInt();
int index = binarySearch(a,b);
System.out.println(index == -1 ? "该元素不存在!" : "该元素下标:"+index);
}
//@return -1表示该元素不存在,其他的表示返回该元素的下标
private static int binarySearch(int[] a,int dest) {
int begin = 0;
int end = a.length-1;
while (begin <= end) {
int mid = (begin + end) / 2;
if (a[mid] == dest) {
return mid;
} else if (a[mid] < dest) {
//目标在”中间“右边
//开始元素小标需要发生变化
begin = mid + 1;
} else {
//a[mid] > dest
//目标在“中间”左边
end = mid - 1;
}
}
return -1;
}
}
Sting类
public class StringTest {
public static void main(String[] args) {
String a = "a";
String b = "a";
System.out.println(a == b);//true
String c = new String("b");
String d = new String("b");
System.out.println(c == d);//false
//所以字符串之间比较不能使用“==”,“==”不保险,应该调用String类的equals方法
//String类已经重写equals方法
System.out.println(c.equals(d));//true
}
}
关于String类中的构造方法
一、String s =new String(“”);
二、String s = “”;
三、String s =new String(char数组);
四、String s =new String(char数组,起始下标,长度);
五、String s =new String(byte数组);
六、String s =new String(byte数组,起始下标,长度);
public class StringTest {
public static void main(String[] args) {
byte[] b = {97,98,99};//97是a 98是b 99是c
String s1 = new String(b,1,2);
System.out.println(s1);//bc
char[] c = {'我','是','好','人'};
String s2 = new String(c,2,2);
System.out.println(s2);//好人
}
}
char c ="我是好人".charAt(1);
System.out.println(c);//国
compareTo
字符串比较使用
int i = "abc".compareTo("abc");
System.out.println(i);//0
int j = "abc".compareTo("abd");
System.out.println(j);//-1
int h = "abd".compareTo("abc");
System.out.println(h);//1
int k = "bac".compareTo("abc");
System.out.println(k);//1
contains
判断前面的字符串是否包含后面的字符串
System.out.println("HelloWorld".contains("Hello"));//true
System.out.println("HelloWorld".contains("Helle"));//false
endWith
判断当前字符串是否以某个字符串结尾
System.out.println("HelloWorld.java".endWith(".java"));//true
System.out.println("HelloWorld".endWith("Helle"));//false
getBytes
将字符串对象转换成字节数组
byte[] by = "asdasf".getBytes();
for (int i = 0; i < by.length; i++) {
System.out.println(by[i]);//97 115 100 97 115 102
indexOf
判断某个子字符串在当前字符串中第一次出现的索引(下标)
System.out.println("askjhfdiukahdfiuhsad.2315361.kaljhsdfklja".indexOf("jhf"));//3
isEmpty
判断某个字符串是否为空
String s = "";
System.out.println(s.isEmpty);//true
面试题
判断数组长度和判断字符串长度不一样
判断数组长度是length属性,判断字符串长度是length()方法
lastIndexOf
判断某个子字符串在当前字符串中最后一次出现的索引(下标)
System.out.println("askjhfdiukahdfiuhsad.2315361.kaljhsdfklja".lastIndexOf("jh"));//32
replace
替换
String s ="www.baidu.com".replace("www.","http://");
System.out.println(s);//http://baidu.com
split
拆分字符串
String s = "www=baidu=com";
String[] ss =s.split("=");
for (int i = 0; i < ss.length; i++) {
System.out.println(ss[i]);//www baidu com
}
startsWith
System.out.println("HelloWorld.java".endWith("Hello"));//true
System.out.println("HelloWorld".endWith("World"));//false
substring
截取字符串
String s = "www.baidu.com";
System.out.println(s.substring(4));//baidu.com
System.out.println(s.substring(4,7));//bai
toCharArray()
将字符串转换成char数组
char[] c = "我是好人".toCharArray();
for (int i = 0; i < c.length; i++) {
System.out.println(c[i]);//我 是 好 人
}
toLowerCase()和toUpperCase()
转换为大小写
String s = "WWWbaiducom";
System.out.println(s.toUpperCase());//WWWBAIDUCOM
System.out.println(s.toLowerCase());//wwwbaiducom
trim()
去除字符串前后空白
System.out.println(" jahsdjkhakjs askljdklasj ".trim());//jahsdjkhakjs askljdklasj
valueOf
将“非字符串”转换成“字符串”
凡是**System.out.println();**的都是字符串
String s = String.valueOf(true);//true字符串
String s1 = String.valueOf(100);//100字符串
System.out.println(true);//字符串
StringBuffer()
//创建一个初始容量为16个byte[]数组(字符串缓冲区对象)
StringBuffer st = new StringBuffer();//可以在括号中给定初始化容量
st.append(465);
st.append("asdad");
st.append(3.14);
st.append(456L);
System.out.println(st);//465asdad3.14456
如何优化StringBuffer的性能?
- 在创建StringBuffer的时候尽可能的给定一个初始化容量
- 最好减少底层数组的扩容次数,预估计一下,给一个大一些初始化容量
StringBuffer和StringBuilder的区别?
- StringBuffer是线程安全的
- StringBuild是非线程安全的
包装类
为什么要再提供8种包装类?
-
因为8种基本数据类型不够用。
基本数据类型 包装类型
byte java.long.Byte(父类Number)
short java.long.Shory(父类Number)
int java.long.Integer(父类Number)
long java.long.Long(父类Number)
float java.long.Float(父类Number)
double java.long.Double(父类Number)
boolean java.long.Boolean(父类Object)
char java.long.Character(父类Object)
Number是一个抽象类,无法实例化对象
//基本数据类型-(转换)——>引用数据类型(装箱)
Integer i = new Integer(456);
//引用数据类型-(转换)——>基本数据类型(拆箱)
float f = i.floatValue();
System.out.println(f);//456.0
MAX_VALUE和MIN_VALUE
System.out.println(Integer.MAX_VALUE);//2147483647
System.out.println(Integer.MIN_VALUE);//-2147483648
自动装箱和自动拆箱
自动装箱:基本数据类型自动转换成包装类(基本数据类型–(自动转换)–>包装类型:自动装箱)
Integer x = 900;
自动拆箱:包装类自动转换成基本数据类型(包装类型–(自动装箱)–>基本数据类型:自动拆箱)
int y = x;
Integer a = 128;
Integer b = 128;
System.out.println(a == b);//false
/*java中为了提高程序的执行效率,将[-128到127]之间的所有包装对象提前创建好,放到了一个方法区的“整数型常量池”当中,目的是只要用这个区间的数据不需要再new了,直接从整数型常量池当中取出来*/
Integer c = 127;
Integer d = 127;
System.out.println(c == d);//true
Data
Date–>String
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateTest {
public static void main(String[] args) {
Date d = new Date();
System.out.println(d);//Fri Oct 30 21:04:01 CST 2020
//格式化Data
SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String s = sd.format(d);
System.out.println(s);//2020-10-30 21:04:01
}
}
String–>Date
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateTest {
public static void main(String[] args) throws Exception{
//String-->Date
String t = "2020-10-30 21:21:50";
SimpleDateFormat sd2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d1 = sd2.parse(t);
System.out.println(d1);//Fri Oct 30 21:21:50 CST 2020
}
}
currentTimeMillis()
获取自1970年1月1日到系统当前时间的总毫秒数
public class DateTest {
public static void main(String[] args) throws Exception{
long begin = System.currentTimeMillis();
print();
long end =System.currentTimeMillis();
System.out.println("输出耗费"+(end-begin)+"毫秒");//输出耗费9毫秒
}
public static void print(){
for (int i = 0; i < 100; i++) {
System.out.println("i="+i);
}
}
}
DecimalFormat()
关于数字的格式化
#代表任意数字
,代表千分位
.代表小数点
0补位
BigDecimal
属于大数据,精度极高,不属于基本数据类型,属于Java对象(引用数据类型)
专门用在财务方面
Random
import java.util.Random;
public class random {
public static void main(String[] args) {
//创建随机数
Random r = new Random();
//随机产生一个int类型取值范围内的数字
int i = r.nextInt();
System.out.println(i);//-595707239
//产生[0~100]之间的随机数,不能产生101
int i1 = r.nextInt(101);
System.out.println(i1);//11
}
}
import java.util.Arrays;
import java.util.Random;
//生成5个不相同的随机数
public class random {
public static void main(String[] args) {
Random r = new Random();
int[] a =new int[5];
for (int i = 0; i < a.length; i++) {
a[i]=-1;
}
int index = 0;
while (index < a.length){
int num = r.nextInt(6);
System.out.println("生成的随机数:"+num);//1 4 2 5 2 3
if(!contain(a,num)){
a[index++]=num;
}
}
for (int i = 0; i < a.length; i++) {
System.out.println(a[i]);//1 4 2 5 3
}
}
public static boolean contain(int[] a,int key){
/*Arrays.sort(a);
return Arrays.binarySearch(a, key) >=0;
存在bug*/
for (int i = 0; i < a.length; i++) {
if (a[i] == key){
return true;
}
}return false;
}
}
enum
如果返回值是2种,建议用Boolean;如果是多种,建议用enum
public class enumTest {
public static void main(String[] args) {
Result r1 = divide(10,5);
Result r2 = divide(10,0);
System.out.println(r1 == Result.SUCCESS ? "计算成功" : "计算失败");//计算成功
System.out.println(r2 == Result.SUCCESS ? "计算成功" : "计算失败");//计算失败
}
public static Result divide(int a ,int b){
try {
int c = a / b;
return Result.SUCCESS;
} catch(Exception e){
return Result.FAIL;
}
}
}
enum Result{
SUCCESS,FAIL
}
异常处理机制
Java异常的作用:增强程序健壮性。
Java异常以类和对象的形式存在。
异常对象的两个方法:
String msg = e.getMessage();
e.printStackTrace();
finally
面试题:
public class finallyTest {
public static void main(String[] args) {
int r = m() ;
System.out.println(r); //100
}
public static int m(){
int i = 100;
try {
//Java方法中有一条语法规则:return语句一旦执行,整个方法必须结束
return i;
//System.exit(0);执行后退出JVM,finally语句中的代码不执行
}finally {
i++;
}
}
}
自己创建异常
创建:
//编写一个类继承Exception或者RunTimeException
//一个带有String参数的,一个无参数的
public class MyException extends Exception{
//编译时异常
public MyException(){
}
public MyException(String s){
super(s);
}
}
/*public class MyException extends RuntimeException{
//运行时异常
}*/
运行:
public class MyExceptionTest {
public static void main(String[] args) {
//创建异常对象(只new了异常对象,并没有手动抛出)
MyException e = new MyException("用户名不能为空!");
//打印异常堆栈信息
e.printStackTrace();//MyException: 用户名不能为空! at MyExceptionTest.main(MyExceptionTest.java:4)
//获取异常简单描述信息
String m = e.getMessage();
System.out.println(m);//用户名不能为空!
}
}
**注意:**重写之后的方法不能比重写前的方法抛出更多的异常,可以更少
集合
所有的实现类:
- ArrayList:底层是数组
- LinkedList:底层是双向链表
- Vector:底层是数组,线程安全,效率较低,使用较少
- HashSet:底层是HashMap,放到HashSet集合中的元素等同于放到HashMap集合key部分
- TreeSet:底层是TreeMap,放到TreeSet集合中的元素等同于放到TreeMap集合key部分
- HashMap:底层是哈希表
- Hashtable:底层是哈希表,只不过线程安全的,效率较低,使用较少
- Properties:是线程安全的,并且key和value只能存储字符串String
- TreeMap:底层是二叉树,TreeMap集合的key可能自动按照大小顺序排序
List集合存储元素的特点:
有序可重复
有序:存进去和取出的顺序相同
Set集合存储元素的特点:
无序不可重复
无序:存进去和取出的顺序不一定相同
SortedSet集合存储元素的特点:
首先是无序不可重复的,但是SortedSet集合中的元素是可排序的
import java.util.ArrayList;
import java.util.Collection;
public class CollectionTest {
public static void main(String[] args) {
Collection c =new ArrayList();
c.add(200);//自动装箱
c.add(true);
c.add(3.14);
c.add(new Student());
c.add(new Object());
c.add("浩克");
System.out.println("集合中的个数有"+c.size());//集合中的个数有6
boolean b = c.contains("浩克");
System.out.println(b);//true
boolean bo = c.contains(201);//false
System.out.println(bo);
c.remove("浩克");
System.out.println("集合中的个数有"+c.size());//集合中的个数有5
System.out.println(c.isEmpty());//false,判断是否为空
c.clear();
System.out.println(c.isEmpty());//true
System.out.println("集合中的个数有"+c.size());//集合中的个数有0
//转换成数组,了解,使用不多
c.add(true);
c.add(3.14);
Object[] o = c.toArray();
for (int i = 0; i < o.length; i++) {
//遍历数组
Object ob = o[i];
System.out.println(ob);//true 3.14
}
}
}
class Student {
}
迭代
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
public class MyArraylistTest {
public static void main(String[] args) {
//遍历/迭代方式,是所有Collection通用的一种方式
//在Map集合中不能使用,在所有的Collection以及子类中能使用
//创建集合对象
Collection c = new HashSet();
c.add("ac");
c.add(3);
c.add(3.14);
c.add(new Object());
//对集合进行遍历/迭代
//第一步:获取迭代器对象
Iterator i = c.iterator();
//第二步:通过获取的迭代器开始迭代
/*以下两个方法是迭代器对象iterator中的方法:
boolean hasNext()如果仍有元素可以迭代,则返回true
Object next() 返回迭代的下一个元素*/
while(i.hasNext()){
boolean h = i.hasNext();
//不管你存进去什么,取出来统一都是Object
Object o = i.next();
System.out.println(o);
/* java.lang.Object@10f87f48
ac
3
3.14*/
}
}
}
迭代集合和HasSet集合
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
public class MyArrayList {
public static void main(String[] args) {
//创建集合对象
Collection c = new ArrayList();//ArrayList集合:有序可重复
//添加元素
c.add(1);
c.add(2);
c.add(3);
c.add(1);
//迭代集合
Iterator i = c.iterator();
while (i.hasNext()){
Object o = i.next();
System.out.println(o);//1 2 3 1
}
//HasSet集合:无序不可重复
Collection co = new HashSet();
//无序:存进去的顺序和取出来的顺序不同 不可重复:存进去100后,不能再次存储
co.add(100);
co.add(200);
co.add(300);
co.add(400);
co.add(30);
co.add(40);
co.add(100);
Iterator it = co.iterator();
while (it.hasNext()){
System.out.println(it.next());//400 100 200 40 300 30
}
}
}
contains方法
contains方法是用来判断集合中是否包含某个元素的方法,在底层中调用了equals方法进行比对,返回true。就表示包含这个元素
package collec;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;
public class mycollection {
public static void main(String[] args) {
//创建集合对象
Collection c = new ArrayList();
//创建用户对象
User u1 = new User("李四");
User u2 = new User("李四");
c.add(u1);
//没重写equals方法之前
//System.out.println(c.contains(u2));//false
//重写equals方法之后
System.out.println(c.contains(u2));//true
}
}
class User{
private String name;
public User(){}
public User(String name){
this.name = name;
}
//重写equals方法
//这个equals方法的比较原理:只要名字一样就表示同一个用户
@Override
public boolean equals(Object o) {
if (o == null || !(o instanceof User)) return false;
if (this == o) return true;
User user = (User) o;
//如果名字一样,表示同一个人
return user.name.equals(this.name);
}
}
remove
package collec;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
//当集合的结构发生改变时,迭代器必须重新获取
public class MycollectionTest {
public static void main(String[] args) {
Collection c = new ArrayList();
//Iterator i = c.iterator();//ConcurrentModificationExceptionm,集合结构改变,所以会报错
c.add(1);
c.add(2);
c.add(3);
c.add(1);
Iterator i = c.iterator();
while (i.hasNext()){
Object o = i.next();
//c.remove(o);//ConcurrentModificationException,迭代器结构改变,在迭代集合工程中,不能调用集合对象的remove方法删除元素
//因为c.remove(o);直接通过集合去删除元素,没有通知迭代器(导致迭代器的快照和原集合状态不同)
//出异常的根本原因是:集合中元素删除了,但是没有更新迭代器(迭代器不知道集合变化)
i.remove();//可以使用迭代器删除元素,删除的一定是迭代器指向的当前元素
//迭代器去删除时,会自动更新迭代器,并且更新集合,(删除集合中的元素)
System.out.println(o);
}
System.out.println(c.size());//元素为0
}
}
List
package collec;
import java.util.*;
/*测试List接口中常用的方法
List集合存储元素的特点:有序可重复
有序:List集合中的元素有下标。从0开始,以1递增
可重复:存储一个1,还可以继续存储1*/
public class ListTest01 {
public static void main(String[] args) {
//List mylist = new LinkedList();
//List mylist = new Vector();
List mylist = new ArrayList();
mylist.add("asd");//默认向集合末尾添加元素
mylist.add("aqw");
mylist.add("qwe");
mylist.add(1,"li");//在列表指定位置插入指定元素,用的比较少,因为效率较低
Iterator it = mylist.iterator();
while (it.hasNext()){
Object o = it.next();
System.out.println(o);//asd li aqw qwe
}
//根据下标获取元素
Object firo = mylist.get(2);
System.out.println(firo);//aqw
//因为有下标,所以List集合有自己比较特殊的遍历方式
//通过下标遍历[List集合特有的方法,Set没有]
for (int i = 0; i < mylist.size(); i++) {
Object obj = mylist.get(i);
System.out.println(obj);//asd li aqw qwe
}
//获取指定对象第一次出现处的索引
System.out.println(mylist.indexOf("qwe"));//3
//获取指定对象最后一次出现处的索引
System.out.println(mylist.lastIndexOf("li"));//1
//删除指定下标位置的元素
mylist.remove(3);
System.out.println(mylist.size());//3
//修改指定位置的元素
mylist.set(2,"yun");
for (int i = 0; i < mylist.size(); i++) {
Object b = mylist.get(i);
System.out.println(b);//asd li yun
}
}
}
**面试官常问一个问题:**你用哪个集合比较多
答:ArrayList集合。因为往数组末尾添加元素,效率不受影响。另外,我们检索/查找某个元素的操作比较多
-
数组优点:
- 检索效率比较高。(每个元素占用空间大小相同,内存地址是连续的,知道首元素内存的地址,然后知道下标,通过数学表达式计算出元素的内存地址,所以检索效率最高)
-
数组缺点:
- 随机增删元素效率比较低
- 另外数组无法存储大数据量。(很难找到一块非常巨大的连续的内存空间)
单项链表
package danLike;
public class Link {
Node header;
int size;
public int size(){
return size;
}
//添加元素的方法
public void add(Object data){
if(header == null){
header = new Node(data , null);
}else {
Node currentLastNode = findLast(header);
currentLastNode.next = new Node(data,null);
}
size++;
}
private Node findLast(Node node) {
if (node.next == null){
return node;
}
return findLast(node.next);//递归算法
}
//删除元素的方法
public void remove(Object obj){
}
//修改元素的方法
public void modify(Object newobj){
}
//查找元素的方法
public void find(){
}
}
Vector
package VectorTest;
import java.util.*;
//Vector中所有的方法都是线程同步,都带有synchronizedList关键字
//是线程安全,效率比较低,使用较少
public class VectorTest {
public static void main(String[] args) {
Vector v = new Vector();
//添加元素,默认容量10个
v.add("1");
v.add("2");
v.add("3");
v.add("4");
v.add("5");
v.add("6");
v.add("7");
v.add("8");
v.add("9");
v.add("10");
//满了之后扩容为20
v.add("11");
Iterator iterator = v.iterator();
while (iterator.hasNext()){
Object o = iterator.next();
System.out.println(o);
}
//以后可能要用,非线程安全ArrayList转变为线程安全Collections
List myList = new ArrayList();//非线程安全
//变为线程安全
Collections.synchronizedList(myList);
myList.add("111");
myList.add("222");
myList.add("333");
}
}
泛型
package collec;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class GenericTest01 {
public static void main(String[] args) {
/* //不适用泛型,分析程序缺点
List myList = new ArrayList();
//准备对象
Cat cat = new Cat();
Bird bird = new Bird();
//将对象添加到集合中
myList.add(cat);
myList.add(bird);
Iterator i = myList.iterator();
while (i.hasNext()){
Object o = i.next();
if(o instanceof Animals){
Animals a =(Animals)o;
a.move();
}
}*/
//使用JDK5之后的泛型机制
//使用泛型List<Animals>之后,表示List集合中只允许存储Animals类型的数据
//用泛型来指定集合中存储的数据类型
List<Animals> myList = new ArrayList<Animals>();
Cat cat = new Cat();
Bird bird = new Bird();
//将对象添加到集合中
myList.add(cat);
myList.add(bird);
Iterator<Animals> i = myList.iterator();
while (i.hasNext()){
Animals a = i.next();
//a.move();
if (a instanceof Cat){
Cat c =(Cat)a;
c.catchMouse();
}
if (a instanceof Bird){
Bird b =(Bird)a;
b.fly();
}
}
}
}
class Animals{
public void move(){
System.out.println("动物在移动!");
}
}
class Cat extends Animals{
public void catchMouse(){
System.out.println("猫抓老鼠!");
}
}
class Bird extends Animals{
public void fly(){
System.out.println("鸟儿在飞!!!");
}
}
泛型的自动类型推断机制
package collec;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
//JDK引入:自动类型推断机制(又称为钻石表达式)
public class GenericTest02 {
public static void main(String[] args) {
List<Animals> myList = new ArrayList<>();
Cat c = new Cat();
Bird b = new Bird();
myList.add(c);
myList.add(b);
Iterator<Animals> i = myList.iterator();
while (i.hasNext()){
Animals a = i.next();
a.move();
}
List<String> s = new ArrayList<>();
s.add("www.baidu.com");
s.add("http://zsquw5.coding-pages.com/post/8df0ec14.html");
s.add("https://solitudehero.github.io/");
Iterator<String> it = s.iterator();
while (it.hasNext()){
/* //如果不使用泛型
Object o = it.next();
if (o instanceof String){
String ss = (String)o;
ss.substring(0);
}*/
String s1 = it.next();
String newString = s1.substring(0);
System.out.println(newString);
}
}
}
foreach
public class foreachTest {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6};
//增强for(foreach)
//foreach缺点是没有下标
for (int data : arr){
//data是数组中的元素
System.out.println(data);//1 2 3 4 5 6
}
}
}
HashSet
无序不可重复
import java.util.HashSet;
import java.util.Set;
public class HashSetTest {
public static void main(String[] args) {
Set<String> s = new HashSet<>();
s.add("3");
s.add("2");
s.add("3");
s.add("4");
s.add("1");
//放到HashSet集合中的元素实际上是放到HashMap集合的key部分
for (String str : s){
System.out.println(str);//1 2 3 4
}
}
}
TreeSet
import java.util.Set;
import java.util.TreeSet;
public class TreeSetTest {
public static void main(String[] args) {
Set<String> s = new TreeSet<>();
s.add("a");
s.add("B");
s.add("b");
s.add("A");
s.add("E");
s.add("B");
//无序不可重复,但是存储的元素可以按照大小顺序排序 称为:可排序集合
for (String st : s){
System.out.println(st);//A B E a b
}
}
}
Map
常用的方法(一)
package collec;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class Maptest01 {
/* java.util.Map接口中常用的方法:
1.Map和Collection没有继承关系
2.Map集合以key和value的方式存储数据:键值对
key和value都是引用数据类型
key和value都是存储对象的内存地址
key起主导地位,value是key的一个附属品*/
public static void main(String[] args) {
//创建Map集合对象
Map<Integer,String> m = new HashMap<>();
m.put(1,"1");
m.put(2,"2");
m.put(3,"3");
m.put(4,"4");
m.put(5,"5");
//通过key获取value
String v = m.get(1);//1
System.out.println(v);
//获取键值对的数量
System.out.println("键值对的数量:"+m.size());//键值对的数量:5
//通过key删除key-value
m.remove(2);
System.out.println("键值对的数量:"+m.size());// 键值对的数量:4
//判断是否包含某个key
System.out.println(m.containsKey(4));//true
//判断是否包含某个value
System.out.println(m.containsValue("4"));//true
//获取所有的values
Collection<String> c = m.values();
for(String s : c){
System.out.println(s);//1 3 4 5
}
//清空键值对数量
m.clear();
System.out.println("键值对的数量:"+m.size());// 键值对的数量:0
//判断是否为空
System.out.println(m.isEmpty());//true
}
}
常用的方法(二)
package collec;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Maptest02 {
public static void main(String[] args) {
//第一种方法:通过遍历key来遍历values
Map<Integer,String> map = new HashMap<>();
map.put(1,"1");
map.put(2,"2");
map.put(3,"3");
map.put(4,"4");
map.put(5,"5");
Set<Integer> keys = map.keySet();
//迭代器可以
Iterator<Integer> it = keys.iterator();
while (it.hasNext()){
Integer key = it.next();
//通过key获取values
String value = map.get(key);
System.out.println(key + "=" + value);//1=1 2=2 3=3 4=4 5=5
}
//foreach也行
for(Integer key : keys){
System.out.println(key + "=" + map.get(key));//1=1 2=2 3=3 4=4 5=5
}
//第二种方法:Set<Map,Entry<K,V> entrySet()>
//以上这种方法就是把Map集合全部转换为Set集合
//Set集合中的元素的类型是:Map.Entry
Set<Map.Entry<Integer, String>> set = map.entrySet();
//遍历Set集合,每一次取出一个Node
/* //迭代器
Iterator<Map.Entry<Integer, String>> ite = set.iterator();
while (ite.hasNext()){
Map.Entry<Integer, String> node = ite.next();
Integer key = node.getKey();
String value = node.getValue();
System.out.println(key + " = " + value);//1=1 2=2 3=3 4=4 5=5
}*/
//foreach,效率比较高
for (Map.Entry<Integer,String> node : set){
System.out.println(node.getKey() + " ----> " + node.getValue());//1 ----> 1 2 ----> 2 3 ----> 3 4 ----> 4 5 ----> 5
}
}
}
同时重写hashCode和equals
- Student类
package bean;
import java.util.Objects;
public class Student {
private String name;
public Student(){
}
public Student(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
//重写equals
}
/* public boolean equals(Object o) {
if (o == null || !(o instanceof Student)) return false;
if (o == this) return true;
Student s = (Student) o;
return this.name.equals(s.name);
}*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}
- HashMapTest02
package bean;
import java.util.HashSet;
import java.util.Set;
//1.向Map集合中存,和从Map集合中取,都是先调用key的hashCode方法,然后再调用equals方法!equals方法可能调用,也可能不调用
//2.如果一个类的equals方法重写了,那么hashCode()方法必须重写
//并且equals方法返回如果是true,hashCode()方法返回的值必须一样
public class HashMapTest02 {
public static void main(String[] args) {
Student s1 = new Student("张三");
Student s2 = new Student("张三");
/* //重写equals前
System.out.println(s1.equals(s2));//false*/
//重写equals后
System.out.println(s1.equals(s2));//true'
System.out.println("s1的hashCode="+s1.hashCode());//s1的hashCode=189568618
System.out.println("s1的hashCode="+s2.hashCode());//s1的hashCode=666641942
//s1.equals(s2)结果是true,表示s1和s2是一样的,那么往HashSet集合中放,按说只能放进去一个(HashSet集合特点:无序不可重复)
Set<Student> students = new HashSet<>();
students.add(s1);
students.add(s2);
System.out.println(students.size());//这个结果按理说是1,但实际上是2
}
}
Properties
package collec;
import java.util.Properties;
//Properties是一个Map集合,继承HashTable,Properties的key和value都是String类型
//Properties被称为属性类对象
//Properties是线程安全的
public class PropertiesTest {
public static void main(String[] args) {
Properties pro = new Properties();
pro.setProperty("username","root");
pro.setProperty("password","123");
//通过key获取value
String username = pro.getProperty("username");
String password = pro.getProperty("password");
System.out.println(username);//root
System.out.println(password);//123
}
}
实现比较接口
package collec;
import java.util.Comparator;
import java.util.TreeSet;
public class TreeSetTest01 {
public static void main(String[] args) {
/*//给构造方法传递一个比较器
TreeSet<Wugui> wg = new TreeSet<>(new WuguiComparator());*/
//匿名内部类
TreeSet<Wugui> wg = new TreeSet<>(new Comparator<Wugui>() {
@Override
public int compare(Wugui o1, Wugui o2) {
return o1.age-o2.age;
}
});
wg.add(new Wugui(100));
wg.add(new Wugui(1000));
wg.add(new Wugui(200));
wg.add(new Wugui(400));
wg.add(new Wugui(500));
for (Wugui w : wg){
System.out.println(w);
/* 乌龟{年龄100}
乌龟{年龄200}
乌龟{年龄400}
乌龟{年龄500}
乌龟{年龄1000}*/
}
}
}
class Wugui{
int age;
public Wugui(int age){
this.age = age;
}
@Override
public String toString() {
return "乌龟{" +
"年龄" + age +
'}';
}
}
/*
//自己编辑比较器
class WuguiComparator implements Comparator<Wugui>{
@Override
public int compare(Wugui o1, Wugui o2) {
return o1.age-o2.age;
}
}*/
Collections工具类
package collec;
import java.util.*;
//Collection集合接口,Collections集合工具类,方便集合操作
public class CollectionsTest {
public static void main(String[] args) {
//ArrayList集合不是线程安全的
List<String> list = new ArrayList<>();
//变成线程安全
Collections.synchronizedList(list);
//排序
list.add("123");
list.add("564");
list.add("547");
Collections.sort(list);
for(String s : list){
System.out.println(s);//123 547 564
}
List<Wugui2> wugui = new ArrayList<>();
wugui.add(new Wugui2(100));
wugui.add(new Wugui2(1000));
wugui.add(new Wugui2(1521));
wugui.add(new Wugui2(1060));
//注意:对List集合中的元素排序,需要保证list集合中的元素实现了:Comparable接口
Collections.sort(wugui);
for (Wugui2 w : wugui){
System.out.println(w);//乌龟{年龄100} 乌龟{年龄1000} 乌龟{年龄1060} 乌龟{年龄1521}
}
//对Set集合排序
Set<String> s = new HashSet<>();
s.add("526");
s.add("589");
s.add("532");
s.add("545");
//将Set集合转换为List集合
List<String> l = new ArrayList<>(s);
Collections.sort(l);
for (String s1 : l){
System.out.println(s1);//526 532 545 589
}
}
}
class Wugui2 implements Comparable<Wugui2> {
int age;
public Wugui2(int age) {
this.age = age;
}
@Override
public int compareTo(Wugui2 o) {
return this.age - o.age;
}
@Override
public String toString() {
return "乌龟{" +
"年龄" + age +
'}';
}
}
IO流
- 通过IO可以完成硬盘文件的读和写。
-
一种是按照流的方向进行分类:
- 以内存作为参照物
- 往内存中去,叫做输入,或者叫做读
- 往内存中出来,叫做输出,或者叫做写
- 以内存作为参照物
-
另一种方式是按照读取数据方式不同进行分类:
- 有的流是按照字节的方式读取数据,一次读取1个字节byte,等同于一次读取8个二进制位。
- 这种流是万能的,什么类型都可以读取。包括文本文件,图片…
- 假设文件file.txt,采用字节流的话读取:
- a中国bc
- 第一次读:一个字节,正好读到’a’
- 第二次读:一个字节,正好读到’中’字符的一半
- 假设文件file.txt,采用字节流的话读取:
- 有的流是按照字符的方式读取数据,一次读取一个字符,这种流是为了方便读取普通文本文件而存在的,这种流不能读取:图片,声音…只能读取文本文件,连word文件都不能读取。
- 假设文件file.txt,采用字符流的话读取:
- a中国bc
- 第一次读:'a’字符('a’字符在Windows系统中占用1个字节)
- 第二次读:'中’字符('中’字符在Windows系统中占用2个字节)
- 假设文件file.txt,采用字符流的话读取:
FileInputStream
文档放入:abcde
package com.java.ioTest;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
java.io.FileInputStream:
1.文件字节输入流,万能的,任何类型的文件都可以采用这个流来读
2.字节的方式,完成输入的操作,完成读的操作(硬盘——>内存)
*/
public class FileInputStreamTest01 {
public static void main(String[] args) {
FileInputStream f = null;
//创建文件字节输入流对象
try {
//FileInputStream f = new FileInputStream("G:\\temp.txt");
f = new FileInputStream("G:/temp.txt");//也可以这么写
//开始读
int read = f.read();//这个方法的返回值是:读取到的“字节”本身
System.out.println(read);//97
read = f.read();//97
System.out.println(read);//98
read = f.read();
System.out.println(read);//99
read = f.read();
System.out.println(read);//100
read = f.read();
System.out.println(read);//101
//已经读到了文件的末尾,再读的时候已经读不到任何数据了,返回-1
read = f.read();
System.out.println(read);//-1
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//在finally语句块中确保流关闭
if (f == null) {//避免空指针异常
//关闭流的前提是:流是null的时候没必要关闭
try {
f.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
循环输出
package com.java.ioTest;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileInputStreamTest02 {
/*
程序缺点:
一次读取一个字节byte,这样内存和硬盘交互太频繁,基本时间都浪费在交互上面。
*/
public static void main(String[] args) {
FileInputStream f = null;
//创建文件字节输入流对象
try {
//FileInputStream f = new FileInputStream("G:\\101");
f = new FileInputStream("G:/temp.txt");//也可以这么写
//循环读
while (true){
int read = f.read();
if (read == -1){
break;
}
System.out.println(read);
}
//改造while循环
int readdate = 0;
while ((readdate = f.read()) != -1){
System.out.println(readdate);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//在finally语句块中确保流关闭
if (f == null) {//避免空指针异常
//关闭流的前提是:流是null的时候没必要关闭
try {
f.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
创建byte数组
package com.java.ioTest;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/*int read(byte[] b)
一次最多读取b.length个字节
减少硬盘和内存你的交互,提高程序的执行效率
在byte[]数组当中读*/
public class FileInputStreamTest03 {
public static void main(String[] args) {
FileInputStream f = null;
try {
//相对路径是工程Project的根就是IDEA的默认当前路径
f = new FileInputStream("temp.txt");
//开始读,采用byte数组,一次读取多个字节,最多读取“数组.length”个字节
byte[] bytes = new byte[4];
//这个方法的返回值是:读取到的字节数量(不是字节本身)
int read = f.read(bytes);
System.out.println(read);//第一次读取到了4个字节
//将字节转换成字符串
// System.out.println(new String(bytes));//abcd
//不应该全部都转换,应该是读取多少个字节,转换多少个
System.out.println(new String(bytes,0,read));//abcd
read = f.read(bytes);
System.out.println(read);//第二次读到了1个字节'
// System.out.println(new String(bytes));//ebcd
//不应该全部都转换,应该是读取多少个字节,转换多少个
System.out.println(new String(bytes,0,read));//e
read = f.read(bytes);
System.out.println(read);//一个字节都没有读取到 -1
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (f != null) {
try {
f.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
最终版
package com.java.ioTest;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
//最终版
public class FileInputStreamTest04 {
public static void main(String[] args) {
FileInputStream f = null;
try {
f = new Fi