Java基础知识:
jdk12需要自己来配置jre,
一个类可以生成一个class文件
main函数的参数类型可以有多种形式
Java基本数据类型:
(4类8种)
整数类型:byte short int long
byte(一个字节)
short(两个字节)
int(四个字节)
long(8个字节) 写数值的时候默认是int,所以后边要加上long.
浮点类型:float double (加小数点,或者科学计数法)
默认浮点类型是double,使用float后边要加f。
字符类型:char
布尔类型:boolean 1位
引用数据类型:
类
接口
数组
在类内,方法外定义的变量叫成员变量,会存在默认值
在方法内,定义的变量必须要进行初始化操作,不会存在默认值
单目运算符:++
多态:
对应同一个指令(调用同一个方法的名称,不同的对象给予不同的反应(不同的方法实现)
规范:
1.必须要有继承关系
2.子类方法必须重写父类的方法
3.父类引用指向子类对象
java中的继承关系是单继承,如果拥有多个父类的时候,可以考虑使用接口,Java中的接口具备广泛的使用。
接口:
实现类可以实现多个接口
接口不能被实例化
接口的子类必须要实现接口中的所有方法,跟抽象类有所不同。
接口中的方法和常量无论是否添加public修饰,默认的权限有且仅有一个public。
接口中的变量都是静态常量,如果常量没有使用static关键字,也表示的是常量。
注意: extends必须位于implements之前
内部类:
一个java文件中可以包含多个类, 但是只能有一个public class,如果一个类定义在另一个类的内部,此时可以称为内部类。
内部类可以方便的访问外部类的私有属性。
外部类不能访问内部属性,但是如果创建了内部类的对象,此时可以在外部类中访问私有属性。
内部类不能定义静态属性
当内部类和外部类具有相同的私有属性的时候,在内部类中访问的时候,可以直接访问内部类的属性,如果需要访问外部类的属性,那么需要添加外部类类名.this.属性。
分类:
匿名内部类:适合只需要使用一次的内部类。考虑到代码编写的简洁,可以考虑不创建具体的类。
静态内部类:在内部类中可以定义静态内部类,使用static关键字进行修饰,使用规则外部类,内部类 类的引用名称=new外部类.静态内部类。
方法内部类:在外部类的方法中也可以定义类,此时叫做方法内部类(了解即可)
使用的时候需要注意,只能在方法中创建对象,因为此class的作用域就是当前方法
当方法需要传递参数时注意。
异常:
在程序运行过程中,出现的不正常情况叫做异常。
捕获异常: try catch finally
声明异常: throws
抛出异常: throw
e.printStackTrace():打印异常的堆栈信息。
注意:当使用多重catch的时候一定要注意相关异常的顺序,将子类放在最前面的catch,父类放在后面的catch。
finally中的代码总会执行,不管包不包含错误都会执行。 IO流的关闭操作一般在finally中,数据库的的关闭操作一般在finally中。
除非在try块或者catch块中调用了退出虚拟机的方法(即System.exit(1);),否则不管在try块、catch块中执行怎样的代码,出现怎样的情况,异常处理的finally块总是会被执行的。
除此之外,可以将异常向外抛出,由外部来进行处理。
包装类:
包装类是将基本数据类型封装成一个类,包含属性和方法。
使用:
在使用过程中,会涉及到自动装箱和自动拆箱
装箱:将基本数据类型转换成包装类Integer.valueOf(a)
拆箱:将包装类转换成基本数据类型i.intValue();
Integer:
数值-128到128之间会取到cache的指定对象
数值超过这个范围会新建对象。
Double:
每次都会New一个对象
常量池在1.7之后放置在了堆空间之中。
字符串:
字符串的本质是字符数组或者叫做字符序列。
String类使用final修饰,不可以被继承。
hashcode源码:返回一个int值。
StringBuffer和StringBuilder:
StringBuffer:是线程安全的,因为每个方法都有一个 synchronized修饰,效率低。
StringBuilder:线程不安全,效率高。
Java集合框架:
Collection:存放的是单一值。
api方法:
add:要求必须传入的参数是Object对象,因此当写入基本数据类型的时候,包含了自动装箱和自动拆箱的过程。
addAll:将另一个集合的元素添加到此集合中。
clear:只是清空集合中元素,但是此集合对象并没有被回收。
contains:判断集合中是否包含指定的元素值。
containsAll:判断此集合中是否包含另一个集合。
retainsAll:若集合中拥有另一个集合的所有元素。返回true,否则返回false。
toArray:将集合转换成数组。
特点:
可以存放不同类型的数据,而数组只能存放固定类型的数据。
当使用arraylist子类实现的时候,长度是10,如果长度不够的话会自动进行扩容操作。
Collection接口中存储一组不唯一,无序的对象
List接口中存储一组不唯一,有序(插入顺序)的对象。
Set接口存储一组唯一,无序的对象。
Map接口中存储一组键值对象,提供key到value的映射。
ArrayList底层就是采用的一个数组:
LinkedList底层采用链表存储方式:
Vector:
Vector也是List接口的一个子类实现
Vector跟ArrayList一样,底层都是使用数组实现的
面试经常问区别:
1.ArrayList是线程不安全的,效率高,Vector是线程安全的(用synchronized修饰),效率低。
2.ArrayList在进行扩容的时候,是扩容1.5倍,Vector是扩容两倍。
所有的集合类都默认实现了Iterable的接口,实现此接口意味着具备了增强for循环的能力,也就是for-each.
增强for循环本质上使用的也是iterator的功能。
在iterator的方法中,要求返回一个Iterator的接口子类实例对象,此接口中包含了hasNext(),next()。
ListIterator迭代器提供了向前和向后的两种遍历方式。
始终是通过cursor和lastret的指针来获取元素值及向下的遍历索引
当使用向前遍历的时候必须要保证指针在迭代器的结尾,否则无法获取结果。
Set
set中存放的是无序唯一的数据。底层用的红黑树。
set不可以通过下标获取对应位置的元素值,因为是无序的特点。
使用treeset底层的实现是treemap,利用红黑树来进行实现。
设置元素的时候,如果是自定义对象,会查找对象中的equals和hashcode方法,需要重写这两个方法,如果不重写会自动比较两个对象的地址。
总结:
HashSet是如何保证元素的唯一性呢?
答:是通过元素的两个方法,hashCode和equals方法来完成
如果元素的HashCode值相同,才会判断equals是否为true
如果元素的hashCode值不同,不会调用equals方法。
HashSet TreeSet以及泛型
左旋:逆时针旋转,父节点被自己的右孩子取代,而自己成为自己的左孩子。
右旋:顺时针旋转,父节点被左孩子取代,而自己成为自己的右孩子。
TreeSet
采用二叉树(红黑树)的存储结构
优点:有序(排序后的升序)查询速度比List快
缺点:查询速度没有HashSet块
HashSet
树中的元素是要默认进行排序操作的,如果是基本数据类型,自动比较,如果是引用数据类型的话,需要自定义比较器。
比较器分类:
内部比较器:
定义在元素的类中,通过实现compareable接口来进行实现
public class People implements Comparable { private String name; private int age; public People(String name, int age) { this.name = name; this.age = age; } /** * 通过名字的长度来比较 * @param o the object to be compared. * @return */ @Override public int compareTo(Object o) { People p= (People) o; if(this.name.length()>p.name.length()){ return 1; }else if(this.name.length()<=p.name.length()){ return -1; }else{ return 0; } } }
外部比较器:
定义在当前类中,通过实现comparator接口来实现,但是要将该比较器传递到集合中
注意:外部比较器可以定义成一个工具类,如果有需要,可以复用,而内部比较器只有在存储当前对象的时候才可以使用。如果两者同时存在使用外部比较器。
当使用比较器的时候不会调用equals方法。
public class Cat implements Comparator<Cat> { private String name; private int age; public static void main(String[] args) { TreeSet treeSet=new TreeSet(new Cat()); } /** * 通过年龄来比较 * @param o1 the first object to be compared. * @param o2 the second object to be compared. * @return */ @Override public int compare(Cat o1, Cat o2) { if(o1.age>o2.age){ return 1; }else if(o1.age<=o2.age){ return -1; }else{ return 0; } } }
List
list可以创建任何元素值
泛型
当做一些集合的统一操作的时候,需要保证集合的类型是统一的,此时需要泛型来进行限制。
优点:
1.数据安全
2.获取数据时效率比较高
给集合中的元素设置相同的类型就是泛型的基本需求。
使用:
1.在定义对象的时候,通过<>设置合理的类型来进行实现
泛型的高阶应用:
1.泛型类
在定义类的时候可以在类名的后面添加字母。类中的方法的返回值类型和属性的类型都可以使用。
定义泛型类
public class FanXingClass <T>{ private int id; private T t; public int getId() { return id; } public void setId(int id) { this.id = id; } public T getT() { return t; } public void setT(T t) { this.t = t; } public T getaT(){ return t; } }
泛型类的使用:
public static void main(String[] args) { // TreeSet treeSet=new TreeSet(new Cat()); FanXingClass<String> f1=new FanXingClass<String>(); f1.setT("xuyuan"); f1.setId(2); System.out.println(f1); FanXingClass<People> f2=new FanXingClass<People>(); f2.setT(new People("lala",20)); System.out.println(f2); }
2.泛型接口
在定义接口的时候,在接口的名称后添加
子类在实现的时候可以不填写泛型的类型,此时在创建具体的子类对象的时候才决定使用什么类型。
子类在实现泛型接口的时候,只在实现父类的接口的时候指定父类的泛型类型即可,此时,测试方法中的泛型类型必须跟子类保持一致。
接口:
public interface FanXingInterface <T>{ public T test1(); public void test2(); }
接口实现类:
public class FanXingInterfaceSub implements FanXingInterface<String>{ @Override public String test1() { return "a"; } @Override public void test2() { } }
3.泛型方法
在定义方法的时候,指定方法的返回值和参数是自定义的占位符,可以是 类名中的T,也可以是自定义的Q,只不过在使用Q的时候需要使用定义在返回值的前面。
泛型方法的使用:
public class FanXingMethod <T>{ private T t; public T getT() { return t; } public void setT(T t) { this.t = t; } public<Q> void show(Q q){ System.out.println(q); System.out.println( t); } }
FanXingMethod<String> fxm=new FanXingMethod<String>(); fxm.setT("ttt"); fxm.show("123");
4.泛型的上限(工作中不用)
如果父类确定了,所有的子类都可以直接使用。
5.泛型的下限(工作中不用)
如果子类确定了,子类的所有父类都可以直接传递参数使用。
(迭代器自己补)