个人 javase 知识点杂谈,全写一起有点长,内容太多的我会单开文章说明
DOS 知识
操作 | 操作 |
---|---|
cd | 打开目录 |
dir | ls |
cls | 清屏 |
tab | 自动补齐 |
数据类型
整型
int a = 15;
int b = 015;//八进制
int c = 0x15;//16进制
int d = 0b1101;// 二进制
byte e = 127; //一个字节存储 -128~127
short //两个字节存储 -32768~32767
int //四个字节存储
long //八个字节存储
long globalPopulation = 74000000000L;
浮点型
float a = 3.14F;//四个字节 精度小数点后7位
double b = 6.26;//八个字节 精度是float两倍
//浮点类型默认double
// 浮点型比较不精确 如果需要比较需要使用 BigDecimal类
float a = 0.1F;
double b = 1.0/10;
System.out.println(a == b);
// output false
BigDecimal a1 = new BigDecimal(1.0/10);
BigDecimal b1 = new BigDecimal(0.1);
System.out.println(a1.equals(b1));
Tips
基本数据类型转换
原码补码反码
原码 00000001 =>1
10000001 =>-1
补码 反码+1
反码 负数保留符号位其他位取反
0000 0110 =>6
1111 1001 =>-6
字符型
char a ='A'; //两个字节 运算时可以当做整型处理
char b ='\t';
数组
//拷贝方法
/**
* @param src the source array.
* @param srcPos starting position in the source array.
* @param dest the destination array.
* @param destPos starting position in the destination data.
* @param length the number of array elements to be copied.
*/
System.arraycopy(src, srcPos, dest, destPos, length);
代码块
- 普通代码块:定义在方法中,使用{}括起来的代码叫做普通代码块
- 构造代码块:定义在类中的使用{}括起来的代码叫做构造代码块
注意:每次代码运行的时候回将构造代码块中的代码添加到构造方法的前面
构造代码块中的代码会添加到每一个构造方法中,当使用 this(参数)的时候不会添加 - 静态代码块:使用 static{}括起来的代码叫做静态代码块,在程序载入的时候优先执行
数据库连接等其他提前需要准备好的代码会放在 static 代码块 - 同步代码块:
在多线程的时候回使用,用来给共享空间进行加锁操作(后面讲) - 执行顺序:静态代码块–》构造代码块(创建对象的时候才会用到)–》普通代码块
public class CodeBlockDemo {
int a ;
int b;
static{
System.out.println("静态代码块");
}
public CodeBlockDemo(){
System.out.println("无参");
System.out.println("构造方法");
}
public CodeBlockDemo(int a){
this.a = a;
}
public CodeBlockDemo(int a,int b){
//public CodeBlockDemo(int a)
this(a);
this.b = b;
}
{
System.out.println("构造代码块");
}
public void test(){
System.out.println("test");
{
System.out.println("我应该是什么分类");
}
}
public static void main(String[] args) {
CodeBlockDemo codeBlockDemo = new CodeBlockDemo(1,2);
codeBlockDemo.test();
{
System.out.println("main");
}
}
}
接口
接口 has A
抽象类 is A
抽象类和接口区别
1、抽象类中的方法可以有抽象方法,也可以有普通方法,但是接口中只能包含抽象方法
2、抽象类需要使用 abstract 关键字来修饰,而接受使用 interface 关键字来修饰
3、子类使用 extends 关键字来继承抽象类,使用 implements 来实现接口
4、子类继承抽象类的时候必须要实现所有的抽象方法,普通方法可以不重写,而接口中的所有方法必须实现
5、抽象类中可以定义成员变量,而接口中只能定义静态常量
6、抽象类在子类实现的时候是单继承,而接口时多继承
7、抽象类和接口都不能实例化,但是抽象类中可以有构造方法,而接口中不能有构造方法
8、抽象类中可以实现接口,并且不实现接口中方法,而接口只能继承接口,不能实现接口
内部类
内部类(当作类中的一个普通成员变量,只不过此成员变量是 class 的类型):
一个 java 文件中可以包含多个 class,但是只能有一个 public class
如果一个类定义在另一个类的内部,此时可以称之为内部类
-
使用:
创建内部类的时候,跟之前的方法不一样,需要在内部类的前面添加外部类来进行修饰
InnerClassDemo.InnerClass inner = new InnerClassDemo().new InnerClass(); -
特点:
1、内部类可以方便的访问外部类的私有属性
2、外部类不能访问内部类的私有属性,但是如果创建了内部类的对象,此时可以在外部类中访问私有属性
3、内部类中不能定义静态属性
4、当内部类和外部类具有相同的私有属性的时候,在内部类中访问的时候,可以直接访问内部类的属性,
5、如果需要访问外部类的属性,那么需要添加 外部类类名.this.属性。 -
分类:
匿名内部类:当定义了一个类,实现了某个接口的时候,在使用过程中只需要使用一次,没有其他用途
其实考虑到代码编写的简洁,可以考虑不创建具体的类,而采用 new interface(){添加未实现的方法}
就叫做匿名内部类
静态内部类:在内部类中可以定义静态内部类,使用 static 关键字进行修饰,使用规则
外部类.内部类 类的引用名称 = new 外部类.内部类();
方法内部类:在外部类的方法中也可以定义类,此时叫做方法内部类(了解即可)
使用的时候需要注意,只能在方法中创建对象,因为此 class 的作用域就是当前方法
public class Outer {
public static void main(String[] args) {
Face f = new Face();
Face.Nose n = f.new Nose();
n.breath();
Face.Ear e = new Face.Ear();
e.listen();
}
}
class Face {
int type;
String shape = "瓜子脸";
static String color = "红润";
class Nose {
void breath() {
System.out.println(shape);
System.out.println(Face.this.type);
System.out.println("呼吸!");
}
}
static class Ear {
void listen() {
System.out.println(color);
System.out.println("我在听!");
}
}
}
//匿名内部类
public class NoNameInnerClassDemo {
public static void main(String[] args) {
System.out.println("有一万行代码");
new Thread(new Runnable() {
@Override
public void run() {
}
});
System.out.println("有一万行代码");
}
}
//静态内部类
public class StaticClass {
private int id;
public void test(){
System.out.println("test");
}
static class InnerClass{
private String name;
public void show(){
System.out.println("show");
}
}
public static void main(String[] args) {
InnerClass innerClass = new StaticClass.InnerClass();
// InnerClass innerClass = new StaticClass().new InnerClass();
}
}
//方法内部类
public class MethodInnerClass {
public void show(int number){
System.out.println("show");
class InnerClass{
private String name;
public void test(int a){
System.out.println("test");
System.out.println(a);
System.out.println(number);
}
}
new InnerClass().test(12);
}
public static void main(String[] args) {
MethodInnerClass methodInnerClass = new MethodInnerClass();
methodInnerClass.show(1234);
}
}
异常
父类 Throwable
子类 Error Exception
包装类
Integer i = new Integer(100);
Integer.valueOf(100);// -128~127有缓存
//String
//常量池在1.7之后放置在了堆空间里面
//比较
str1.equals(str2);
string str1 ="abc";
String str2 ="abc";
str2=str2.intern();//如果常量池有对应的对象 则会返回对应地址
str1==str2//true
String a ="a"+"b";//一个对象
String b =str1+str2;//三个对象
常用类
字符串相关
StringBuffer 线程安全 效率低
StringBuilder 线程不安全 效率高
日期处理相关
Date
DateFormat
SimpleDateFormat
- parse
- format
public class DateDemo {
public static void main(String[] args) {
DateFormat dateFormat =new SimpleDateFormat("yyyy-MM-dd");
String str =dateFormat.format(new Date());
System.out.println(str);
Calendar calendar =Calendar.getInstance();
//指定时间
calendar.setTime(new Date());
System.out.println(calendar.get(Calendar.YEAR));
}
}
Math
枚举类
public enum EventEnum {
LAUNCH("launch"), PAGEVIEW("pageview"), EVENT("event");
EventEnum(String name) {
this.name = name;
}
private String name;
public void show() {
System.out.println(this.name);
EventEnum[] ee = values();
for (int i = 0; i < ee.length; i++) {
System.out.println(ee[i]);
}
}
}
public class TestEnum {
public static void main(String[] args) {
EventEnum ee =EventEnum.LAUNCH;
ee.show();
String name = EventEnum.PAGEVIEW.name();
System.out.println(name);
}
}
集合
/*
* java集合框架:
* Collection:存放的是单一值
* 特点:
* 1、可以存放不同类型的数据,而数组只能存放固定类型的数据
* 2、当使用arraylist子类实现的时候,初始化的长度是10,当长度不够的时候会自动进行扩容操作
* api方法:
* 增加数据的方法
* add:要求必须传入的参数是Object对象,因此当写入基本数据类型的时候,包含了自动拆箱和自动装箱的过程
* addAll:添加另一个集合的元素到此集合中
*
* 删除数据的方法
* clear:只是清空集合中的元素,但是此集合对象并没有被回收
* remove:删除指定元素
* removeAll:删除集合元素
*
* 查询数据的方法
* contains:判断集合中是否包含指定的元素值
* containsAll:判断此集合中是否包含另一个集合
* isEmpty:判断集合是否等于空
* retainAll:若集合中拥有另一个集合的所有元素,返回true,否则返回false
* size:返回当前集合的大小
*
* //集合转数组的操作
* toArray:将集合转换成数组
* */
List
ArraryList
优点:方便查询
缺点:增删效率低
LinkedList
优点:增删快
缺点:遍历和随机查找效率低
Vector
1、Vector 也是 List 接口的一个子类实现
2、Vector 跟 ArrayList 一样,底层都是使用数组进行实现的
3、面试经常问区别:
(1)ArrayList 是线程不安全的,效率高,Vector 是线程安全的效率低
(2)ArrayList 在进行扩容的时候,是扩容 1.5 倍,Vector 扩容的时候扩容原来的 2 倍(具体可以看源码的 grow 方法)
Iterator
在 java 代码中包含三种循环的方式
do…while
while
for
还有一种增强 for 循环的方式,可以简化循环的编写
所有的集合类都默认实现了 Iterable 的接口,实现此接口意味着具备了增强 for 循环的能力,也就是 for-each
增强 for 循环本质上使用的也是 iterator 的功能
方法:
iterator()
foreach()
在 iterator 的方法中,要求返回一个 Iterator 的接口子类实例对象
此接口中包含了
hasNext()
next()
在使用 iterator 进行迭代的过程中如果删除其中的某个元素会报错,并发操作异常,因此
如果遍历的同时需要修改元素,建议使用 listIterator(),
ListIterator 迭代器提供了向前和向后两种遍历的方式
始终是通过 cursor 和 lastret 的指针来获取元素值及向下的遍历索引
当使用向前遍历的时候必须要保证指针在迭代器的结果,否则无法获取结果值
//ArrayList 内部关于Iterator的具体实现
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];
}
Set
唯一无序
- TreeSet
底层是红黑树
默认有排序操作,如果是基本数据类型,自动比较如果是引用类型,需要自定义比较器- 比较器分类:
内部比较器:定义在元素的类种,继承 Comparable 接口
外部比较器:定义在外部类中,通过实现 Comparator 接口实现,但是要将该比较器传递到集合中(TreeSet treeSet = new TreeSet(new Compare())) - 区别:
外部比较器可以定义成工具类用于复用,而内部比较器只能用于当前类(因为是使用外部构造器的构造方法生成的)
如果两者同时存在,则使用外部比较器 - 当使用比较器的时候不会调用 equals 方法
- 比较器分类:
- HashSet
需要重写 hashCode 和 equals 方法
泛型
保证集合内数据类型统一
优点:
- 数据安全
- 获取数据时效率比较高
List<String> list = new ArrayList();
泛型的高阶应用:
泛型类
常见的 ArrayList<E> 就是泛型类 当然也可以自己定义
泛型接口
//泛型接口
public interface FanXingInterface<B> {
public B test();
public void test2(B b);
}
//子类1
public class FanXingInterfaceSub implements FanXingInterface<String> {
@Override
public String test() {
return null;
}
@Override
public void test2(String string) {
}
}
//测试方法 类型由子类决定 随意改变会报错
FanXingInterfaceSub fxi = new FanXingInterfaceSub() ;
//子类2
public class FanXingInterfaceSub<E> implements FanXingInterface<E> {
@Override
public E test() {
return null;
}
@Override
public void test2(E e) {
}
}
//测试方法 类型由测试方法决定
FanXingInterfaceSub<String> fxi = new FanXingInterfaceSub() ;
泛型方法
在定义方法的时候,指定方法的返回值和参数是自定义的占位符,可以是类名中的 T,也可以是自定义的 Q,只不过在使用 Q 的时候需要使用<Q>定义在返回值的前面
public <Q> void show(Q q)
泛型的上限
如果父类确定了,所有的子类都可以直接使用
泛型的下限
如果子类确定了,子类的所有父类都可以直接传递参数使用
Map
HashMap
- key 无序唯一
- value 无序不唯一
LinkedHashMap
- 有序的 HashMap 速度快
TreeMap
- 有序 速度没有 hash 快
/**
* map存储的是k-v键值对映射的数据
* 实现子类:
* HashMap:数据+链表(1.7) 数组+链表+红黑树(1.8)
* LinkedHashMap:链表
* TreeMap:红黑树
*
* 基本api操作:
* 增加:
* put(k,v) 添加元素
* 查找:
* isEmpty 判断是否为空
* size 返回map的大小
* containsKey
* containsValue
* get
* 删除:
* clear 清空集合中的所有元素
* remove:删除指定元素
* Map.entry:表示的是K-V组合的一组映射关系,key和value成组出现
*
* hashmap跟hashtable的区别:
* 1、hashmap线程不安全,效率比较高,hashtable线程安全,效率低
* 2、hashmap中key和value都可以为空,hashtable不允许为空
*
*
* hashmap初始值为2的N次幂,
* 1、方便进行&操作,提高效率,&要比取模运算效率要高
* hash & (initCapacity-1)
* 2、在扩容之后涉及到元素的迁移过程,迁移的时候只需要判断二进制的前一位是0或者是1即可
* 如果是0,表示新数组和就数组的下标位置不变,如果是1,只需要将索引位置加上旧的数组的长度值即为新数组的下标
* 1.7源码知识点: 数组+链表
* 1、默认初始容量
* 2、加载因子
* 3、put操作
* 1、设置值,计算hash
* 2、扩容操作
* 3、数据迁移的过程
* 1.8源码知识点: 数组+链表+红黑树
*/
public class MapDemo {
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<String,Integer>(13);
map.put("a",1);
map.put("b",2);
map.put("c",3);
map.put("d",4);
map.put(null,null);
System.out.println(map);
System.out.println(map.isEmpty());
System.out.println(map.size());
// map.clear();
System.out.println(map.containsKey("a"));
System.out.println(map.containsValue(2));
System.out.println(map.get("a"));
map.remove("a");
System.out.println(map);
//遍历操作
Set<String> keys = map.keySet();
for(String key:keys){
System.out.println(key+"="+map.get(key));
}
//只能获取对应的value值,不能根据value来获取key
Collection<Integer> values = map.values();
for (Integer i:values){
System.out.println(i);
}
//迭代器
Set<String> keys2 = map.keySet();
Iterator<String> iterator = keys2.iterator();
while(iterator.hasNext()){
String key = iterator.next();
System.out.println(key+"="+map.get(key));
}
//Map.entry
Set<Map.Entry<String, Integer>> entries = map.entrySet();
Iterator<Map.Entry<String, Integer>> iterator1 = entries.iterator();
while (iterator1.hasNext()){
Map.Entry<String, Integer> next = iterator1.next();
System.out.println(next.getKey()+"--"+next.getValue());
}
}
}
Collections
Collection 不同 Collections 是工具类
addAll
sort
binarySearch//二分查找的时候需要先进行排序操作,如果没有排序的话,是找不到指定元素的
fill//替换
shuffle
reverse
Arrays
Collections 相同
//asList demo
// int[] array = new int[]{1,2,3,4,5};
List<Integer> ints = Arrays.asList(1,2,3,4,5);
//list转换成数组
Object[] objects = ints.toArray();
//直接用用数组转换
Integer[] array = new Integer[]{1,2,3,4,5,6};
ArrayList<Integer> arrayList=new ArrayList();
arrayList.add(123);
Collections.addAll(arrayList, array);
System.out.println(arrayList);
容器的一些面试题
1.Collection 和 Collections 的联系和区别
Collection 集接口,Collections 是工具类静态方法来对集合进操作
2.ArrayList 和 LinkedList 的联系和区别
ArrayList 连续遍历元素和随机访问元素较高
LinkedList 才用列表 插入删除元素较高
3.Vector 和 ArrayList 的联系和区别
Vector 线程安全 ArrayList 线程不安全
增加长度时 Vector 默认增长一倍,ArrayList 增长 0.5 倍
4.HashMap 和 HashTable 的联系和区别
HashMap 线程不安全 HashTable 线程安全
HashMap 允许 null HashTable 不允许 null
IO
File 类的常用方法
File file = new File("src/abc.txt");
//创建文件
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
//判断文件的属性,都会返回boolean类型的值
file.canExecute();
file.canRead();
file.canWrite();
//判断当前文件是否存在
System.out.println(file.exists());
//获取文件的名称
System.out.println(file.getName());
//获取文件的绝对路径
System.out.println(file.getAbsolutePath());
//获取文件的父路径名称,如果文件的路径中只包含文件名称,则显示空
System.out.println(file.getParent());
//返回文件绝对路径的规范格式
System.out.println(file.getCanonicalPath());
//返回操作系统的文件分割符
System.out.println(File.separator);
//无论当前文件是否存在,只要给定具体的路径,都可以返回相应的路径名称
File file2 = new File("c:/a/b/c");
System.out.println(file2.getAbsolutePath());
//判断文件是否是文件或者目录
System.out.println(file2.isDirectory());
System.out.println(file2.isFile());
// String[] list = file2.list();
// for(String str:list){
// System.out.println(list.toString());
// }
// System.out.println("---------------");
// File[] files = file2.listFiles();
// for(File f : files){
// System.out.println(f);
// }
//打印当前文件系统的所有盘符
File[] files1 = File.listRoots();
for(int i = 0;i<files1.length;i++){
System.out.println(files1[i]);
}
//创建单级目录
file2.mkdir();
//创建多级目录
file2.mkdirs();
IO 流
字节流
InputStream,OutpuStream
字符流
Reader,Writer
InputStream(抽象类)
以子类 FileInputStream 为例说明
/* 注意:当编写io流的程序的时候一定要注意关闭流
* 步骤;
* 1、选择合适的io流对象
* 2、创建对象
* 3、传输数据
* 4、关闭流对象(占用系统资源)
*/
inputStream = new FileInputStream("abc.txt");
//1.单个读取
int read = inputStream.read();
while((read = inputStream.read())!=-1){
System.out.println((char)read);
}
//2.添加缓冲区的方式进行读取,每次会将数据添加到缓冲区中,当缓冲区满了之后,一次 读取,而不是每一个字节进行读取
int length = 0;
byte[] buffer = new byte[1024];
while((length = inputStream.read(buffer))!=-1){
System.out.println(new String(buffer,0,length));
}
//3.缓冲数组+限定长度
int length = 0;
byte[] buffer = new byte[1024];
// read(byte[] b, int off, int len)
//b - the buffer into which the data is read.
// off - the start offset in array b at which the data is written.
// len - the maximum number of bytes to read.
while((length = inputStream.read(buffer,5,5))!=-1){
System.out.println(new String(buffer,5,length));
}
OutputStream(抽象类)
以子类 FileOutputStream 为例说明
File file = new File("aaa.txt");
OutputStream outputStream = null;
try {
outputStream = new FileOutputStream(file);
outputStream.write(99);
outputStream.write("\r\nabc".getBytes());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Reader(抽象类)
//FileReader
Reader reader = null;
try {
reader = new FileReader("abc.txt");
int read = reader.read();
System.out.println((char)read);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//bufferReader
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("aaa.txt"));
String read = null;
while((read = reader.readLine())!=null){
System.out.println(read);
};
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Writer(抽象类)
/* 什么时候需要加flush,什么时候不加flush
* 最保险的方式,在输出流关闭之前每次都flush一下,然后再关闭
* 当某一个输出流对象中带有缓冲区的时候,就需要进行flush,不建议大家去记住每个输出流的分类
*/
BufferedWriter bufferedWriter = null;
FileWriter fileWriter = null;
try {
fileWriter = new FileWriter(new File("abc.txt"));
bufferedWriter = new BufferedWriter(fileWriter);
bufferedWriter.append("mashibing");
bufferedWriter.newLine();
bufferedWriter.append("马士兵教育");
bufferedWriter.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
字节流字符流转换
// 字节流转字符流
//InputStreamReader
fileInputStream = new FileInputStream(file);
inputStreamReader = new InputStreamReader(fileInputStream);
//OutputStreamWriter
outputStreamWriter = new OutputStreamWriter(fileOutputStream,"iso8859-1");
// 字符流转字节流
//没 如果是字符文件的话直接用字符流读就行
RandomAccessFile
RandomAccessFile 是随机访问文件(包括读/写)的类。它支持对文件随机访问的读取和写入,即我们可以从指定的位置读取/写入文件数据。
需要注意的是,RandomAccessFile 虽然属于 java.io 包,但它不是 InputStream 或者 OutputStream 的子类;它也不同于 FileInputStream 和 FileOutputStream。 FileInputStream 只能对文件进行读操作,而 FileOutputStream 只能对文件进行写操作;但是,RandomAccessFile 同时支持文件的读和写,并且它支持随机访问。
下面是一个分块读取大文件的例子
public class RandomAccessFileTest {
public static void main(String[] args) {
File file = new File("doc.txt");
//整个文件的大小
long length = file.length();
//规定块的大小
int blockSize = 1024;
//文件可以被切分成多少个块
int size = (int)Math.ceil(length*1.0/blockSize);
System.out.printf("要被切成《%d》个块",size);
int beginPos = 0;
int actualSize = (int)(blockSize>length?length:blockSize);
for(int i = 0;i<size;i++){
//每次读取块的时候的起始偏移量
beginPos = i*blockSize;
if(i==size-1){
actualSize = (int) length;
}else{
actualSize = blockSize;
length -=actualSize;
}
System.out.println(i+"---》起始位置是:"+beginPos+"---->读取的大小是:"+actualSize);
readSplit(i,beginPos,actualSize);
}
}
public static void readSplit(int i,int beginPos,int actualSize){
RandomAccessFile randomAccessFile = null;
try {
randomAccessFile = new RandomAccessFile(new File("doc.txt"),"r");
//表示从哪个偏移量开始读取数据
randomAccessFile.seek(beginPos);
byte[] bytes = new byte[1024];
int length = 0;
while((length = randomAccessFile.read(bytes))!=-1){
if(actualSize>length){
System.out.println(new String(bytes,0,length));
actualSize-=length;
}else{
System.out.println(new String(bytes,0,actualSize));
break;
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
randomAccessFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
多线程
参考这篇博客 Post not found: javase-thread
网络
参考这篇博客 Post not found: javase-net