Java
Java SE 标准版
Java EE 企业版
Java ME 微型版
Java 底层由C++写的
javac。exe的作用为将.java文件编译生成.class的文件。
.class文件是最终运行文件,一个Java文件可能生成多个.class文件
Java.exe为运行文件
Javadoc可以将文档注释生成文档
main里面的arg可以随便改
一个class就会生成xxx.class文件,只声明calss默认为private
一个文件只能有一个公开的类,public class的名字必须要和.java文件民称一致
每一个calss都可以定义一个main方法,只需java a或b或c等即可
unicode编码,支持全球语言 utf-8 、utf-16… java采用了unicode
方法执行所需的空间在栈里面分配,栈内存主要存储局部变量
java方法的参数传递为值传递
无法被访问后会被回收
构造方法内存分配是在对象被实例化赋值时才开辟。
构造方法
对象传递的是内存地址,而int 这些变量传递的是值,Java永远就是传递变量保存的值也就是u的地址,int i 的i的值。
This指针
This存在对象的内存空间中,this不能用在static方法中
主类外面的值无法访问,需要new
This在创建构造函数的使用
类名.static方法 和实例.static方法两种形式都可以,但是后面的使用会警告
静态变量在初始化时就创建了内存空间
静态代码块的作用在于类加载时刻有一定需求时使用,如xml配置文件、连接池等,静态代码块只在该类初次使用时执行
实例代码块在构造方法执行前执行,多个实例代码块按自上而下顺序执行
工具类基本上使用了static的方法构造类
私有的,构造方法无法被继承
父类的的方法的访问权限<=子类重写的访问权限,父类保守,子类可以更开放。子类抛出异常只能更少。
静态方法不能覆盖,静态不能多态
父转子是强制转换 子转父为自动转换
Animal a= new Cat();
运行时和编译时是两种形态,运行时是cat的对象,编译时是Animal对象,因此调用两个都有的方法时,控制台是输出cat的方法,而cat有方法,animal没有改方法,会导致编译失败。无法调用该方法。
可以进行强制转换让Cat a2=Cat(a) a2就可以使用Cat的方法了,编译会通过。
编译会通过,但运行时会报错因为编译器a3认为为Animal的类,而bird也是Animal的子类可以通过编译
通过instanceof来表示
Animal a1=new Cat()
类被final修饰后该类不能被继承了,被finally修饰的方法也不能被重写,被finall修饰的变量只能被初次赋值,不可二次赋值
类里面的构造函数的赋值与类里面但在构造方法外面定义属性变量并赋值时是一样的,都在构造方法时赋值。
final的变量赋值必须手动赋值,不能系统默认赋值
final的对象指向一个对象后就一直只能是这个对象,能改对象的内部的属性的值。
public static final 定义常量的方式
import 可以在类前面不用加com.xxxx…的类名了
java.lang包不需要import
类只能进行public 和缺省来修饰
抽象类无法被实例化 抽象类
abstract class xxx{
存在一个默认无参的构造方法
}
Abstract 和 final是对立的
抽象类可以继承抽象类,抽象类的子类也是抽象类
abstract class yyy extend xxx {
也存在一个默认的无参构造方法如:
yyy(){
由于继承了xxx,因此该默认的无参构造方法需要对父类进行构造即存在:super()
}
}
抽象类里面不一定有抽象方法,但抽象方法一定出现在抽象类里面,抽象类可以拥有普通方法。
public abstract void xxx(); 无大括号,抽象方法的定义。
继承抽象类时必须要实现抽象类的抽象方法
接口可以支持多继承
接口中只有常量和抽象方法,接口里的内容都是公开的,都是public,里面写的方法都是 public abstract的(可以省略)里面的常量都是
public static final(前面的可以省略) int
类去实现接口的时候,类里面实现接口的方法时必须为public 因为接口为里面的方法都是public方法,因此子类的访问权限只能大于等于public
接口通常定义行为动作,一般使用了接口需要类去实现的,接口的静态方法和子类也是抽象的可以不实现
has a 表示有 类的属性来表示,is a 表示是 用继承来表示 like a 表示像 用实现关系用接口实现
System.out.print()输出 ;Scaner x=new Scannser System.in 其中x即为键盘输入
JDK根类为Object
上图为toString的方法,返回的是一个类名+@+一个十六进制的值,SUN公司建议每个子类都应该对toString进行重写
输出引用时就会自动调用toString如 User u=new User; println(u);会调用u的toString
Java 对象之间的对象之间的判断是否相等只能使用equal 不能使用== ,==比较的是地址。String类也必须使用equals因为
String x=“ab”; String y=“ab”;String z=new String(“ab”)时,xy是true而xz时为false
&&短路判断
equals和toString都可以在IDEA中生成
Java垃圾回收器在垃圾数量太少或者时间没到可能不会启动,System.gc()会建议Java进行垃圾回收
接口也可以像类一样当形参
java数组长度不可变,数组类型与元素类型统一,所有数组都有length属性,数组存储对象存的都是对象地址,物理存储是连续的。
形参为数组时
main里面的string数组的用途如下:
数组扩容的方法为建立一个大的数组将小的数组放到大的里面
数组拷贝使用了System.arraycopy()
拷贝的JVM情况如上
二维数组的最里面的数组长度可以长度不一
上图为二维数组做形参。
Java中的arrys提供了相应的将算法封装好的方法,
字符串不能修改,new String和直接=“”jvm的存储是不一样的
字符串比较为什么用equals方法的原因
String传ascii码也会输出字符串
字符转String
String.charat找相应的字符
字符串比较大小
字符串是否包含 String.contains(),字符串是否以某某结尾String.endwith().string底层是一个byte数组
String.equalsIgnoeCase 比较大小并忽略大小,String.getbyte()得到byte数组,String.indexOf()第一次出现的索引处,String.lastindexof()字符串最后出现时的索引,String.replace对字符串进行替换,String.spilt()以什么进行分割,拆分后为字符串数组,String.startwith()以什么字符开始,String.toCharArray()将字符串转换成char数组,String.tolowcase()转小写,toupcase转大写。String.trim()去除整个字符串前后的空格
length在数组为属性,String为方法
如果valueof形参为对象时,直接调用toString
数组长度确定就不能修改了,Stringbuffer定义的byte为非final的使得他的数组指针指向可以改变,让原来的数组可以失去引用而被垃圾回收
包装类
其意义在于传参时如果形参为Object时,想要传基本类型时,为了方便开发Sun对基本类型进行了基本数据类型的对象包装
拆箱装箱
因为自动装拆箱
Integer.parseInt(字符串),字符串转int,其他包装类类似Integer.toBinaryString()返回二进制字符串,String.valuOf(),数字转字符
Date xx=new Date()获得当前的时间,更改其时间的格式,除了ymhds这些不变以外其他可以变
System.currentTimeMillis()获取自1970年开始到现在的毫秒数,new Date加参数就是表示加上多少毫秒
random.nextInt(10)生成0-9的随机数
枚举enum的用法,enum xxx{枚举值},使用枚举的方式,xxx.枚举值,枚举值相当于常量。
switch的枚举有点特殊,如下所示season.需要省略
异常实际上是一个类,在发生异常时JVM自动创建了异常的对象
所有异常发生在运行的状态,无论是编译时异常还是运行时异常
以上处理的方式为,main函数也继承throw 向上抛异常,或者在main中进行try {dosome()}catch这个异常
java强转时,如果强转接口类型时,什么类型都可以
集合list不能存基础类型只能存对象,int类型会直接装箱
Treemap底层为二叉树
数组用append 集合用add 数组用length 集合用size()
Contains() 集合是否包含某元素,remove() 去除某个元素,isEmpty()是否为空,toarray()集合转数组,clear()清除集合内的所有元素
迭代器最初不是指向集合的第一个元素,而是指向第一个元素前的一个位置。通过迭代器取集合时,取出来的都是object类型的。
获取迭代器Iterator t=collecton.Iterator();
println输出为String,因为他底层调用了toString方法
hashset调用迭代器时输出为无序和不重复的,colelction.contains底层调用了equals,没有重写equals时比较的是地址,重写equals时,比较的是equals里面的东西
remove也调用了equals
集合只要改变,迭代器一定要重新获取
迭代器里面遍历时,不能通过集合的方式去删除元素,因为迭代器的工作原理是将集合进行一个快照作为其便利的依据,而快照与原集合会不断对比,集合改变了,快照对不上集合会报异常,而通过迭代器删除元素,即iterator.remove,则迭代器会自动更新迭代器,使快照得到更新,并删除集合里的内容
arrayList 第一个add的时候初始化容量为10,底层为数组,扩容时会增加到原来的1.5倍容量(底层进行向右移一位)
linkList也是存在下标的,也可以用get获得,LinkList为双向链表
Vector底层也是一个数组,初始化容量为10,扩容时,扩容到原来的两倍,是线程安全的,效率比较低,用的比较少
iterator的返回值是Object
泛型是编译阶段识别的
泛型默认的类型为Object
自定义泛型
for循环增强,缺点在于没有下标。
set语法,Treeset可以自动从小到大进行排序
Hashset底层为hashMap
Map的所有key为一个集合
set中每一行为一个元素,set中的值为Map.Entry<K,V>
静态内部类可以存在非静态的方法,非静态的方法需要静态内部类new一下才能点出来
map遍历的方式:获取所有key值后遍历,也可以将map变成一个set集合再遍历(效率高)
常见哈希函数
直接定制法 – (常用)
取关键字的某个线性函数为散列地址:Hash(Key)= A*Key + B
除留余数法 – (常用)
设散列表中允许的地址数为m,取一个不大于m,但最接近或者等于m的质数p作为除数,按照哈希函数:Hash(key) = key % p(p<=m)
平方取中法 – (了解)
假设关键字为1234,对它平方就是1522756,抽取中间的3位227作为哈希地址
折叠法 – (了解)
折叠法是将关键字从左到右分割成位数相等的几部分(最后一部分位数可以短些),然后将这几部分叠加求和, 并按散列表表长,取后几位作为散列地址。
数学分析法 – (了解)
设有n个d位数,每一位可能有r种不同的符号,这r种不同的符号在各位上出现的频率不一定相同,可能在某 些位上分布比较均匀,每种符号出现的机会均等,在某些位上分布不均匀只有某几种符号经常出现。可根据 散列表的大小,选择其中各种符号分布均匀的若干位作为散列地址
闭散列
闭散列:也叫开放定址法,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以 把key存放到冲突位置中的“下一个空位置” 中去。
那如何寻找下一个空位置呢?
线性探测:从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止。若数组结束还没有找到空位置,则绕回 0 的位置往后探测。
二次探测: 再次设计一种哈希算法,以之前Hash(x)对元素的关键码 key 计算出的位置为参数,算出不重复的地址。
闭散列的缺点:
存放不难,但是查找和删除比较难。
闭散列最大的问题:
若整个哈希表冲突比较严重,此时查找元素过程就相当于遍历数组,查找效率退化为O(N)
开散列又叫链地址法(开链法),当发生哈希冲突时,让冲突位置变成链表。每一个子链表称为一个桶,各链表的头节点存储在哈希表中。如果冲突特别严重,就意味着小集合的搜索性能也是不佳的。我们就需要继续优化,进行扩容。
Hashmap初始化的大小为16,设置了当容量实用率达到了75%时自动扩容,扩容为2倍扩,容量为2的倍数,不然会损失性能
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B4bors0m-1665038648088)(/Users/fanjiangfeng/Library/Application Support/typora-user-images/image-20220906081356650.png)]()
idea自动生成,类的hashCode和equals方法需要重写
hashmap当某个点上的链表长度超过8,链表会变成红黑树、红黑树节点只剩6个后又变成单链表
Hashset自己生成k值,而hashmap自己输入k值
hashmap的k值和value值都可以为null
hashtable都不可以为空,线程安全的(现有其他方法实现),效率低,使用较少
treeset底层为treemap,treeset自动排序,升序
treeset里面放置自己定义的类时,需要实现comparable接口,在compareto的方法中定义比较的方式,方法中相等返回0,大于返回正数,小于返回负数,否则会报错
也可以compartor接口实现
当比较规则不会发生改变比较固定的时候,建议使用comparable,比较多变的时候comaprator
Truest/treemap的的排序方式为平衡二叉树,中序遍历
List 集合排序需要存储的对象已经实现了comparable接口,set可以转换成list,然后进行排序
以Stream结尾的为字节流,以read、write为结尾的是字符流
所有流都是可关闭的,都有closeable,流是一个管道,需要及时关闭
所有的输出流都是可刷新的,都有flush方法,用完输出流后记得flush一下,强行将未输出的输出完,清空管道
fileinputstream自带继承exception,需要进行try catch处理或throw处理
fielinputestream x=new fileInputeStream(文件路径),int read=x.read(),此时x指向文件里第一个字节,x为字节的ascii,x调用一次read,x指向就往下移动一次。当文件里的字节都读完了在调用read,会返回-1
IDEA的当前路径为当前工程路径
读abcdef时,先把abcd读取了,在读时,只剩下ef,最多只能读取ef,同时,e和f会替换原来bytes的ab
byte转string时的方法为String(byte),通过string(byte,offset,length)来定义byte输出范围
利用available获取文件有多少字节,通过fileinputstream可以全读完
fileread和filewrite是通过char数组进行的,也可以使用String做入参,read和write只能对普通文本起效,而fileoutputstrea和fileinputstream对任何文件都可以使用
DateInputStream和DateOutputStream是配套使用的,普通的文本打开DateoutputStream写的数据显示的是乱码,同时DateOutPutStream的输出顺序也要和DateInputStream的输入顺序一致才能输出。DateInputStram输入时会把当前的变量类型也会输入
printStream 是标准输出流,不需要释放
file是文件和目录的抽象表示 file类的作用,file,.mkdir 和 file.mkdirs是用来创建目录和多重目录,file.creatnewfile()为创建新的文件,file.exies()表示文件是否存在,file.getparentfile()能得到父的文件,file.getabsolutepath()是获取当前目录的路径.
序列化需要继承serializable接口
Java 项目启动时,jvm即为进程,启动后会至少调用两个线程,一个是调用main方法的线程,一个是启动垃圾回收的线程
Java内不同进程之间资源不共享,同一个进程下的各线程,共享方法区和对内存,但是栈不共享。
main方法结束了,其他的线程可能还在进行压栈和弹栈
创建线程的方法为1、继承thread 重写run方法 通过start 的方法启动线程,start()启动了一个线程,在jvm中开辟了一个栈空间,当栈空间开辟完成后start就结束了,新开辟的空间会自动调用run方法。如果只调用run方法,不会启动多线程,必须在主线程中调用start方法
创建线程方法2、通过new thread 来获取新线程,同时通过重写run方法进行
第二种方式更加灵活
获取线程名称
thread.currentthread.getname()获取当前线程的名称
线程同步synchronized
synchronized放在函数上
守护线程(垃圾回收的线程是守护线程)
定时任务,使用schedule
callable的多线程方式可以返回线程的值
反射机制
需要完整的包名,java.lang不能省
通过反射机制创建实例对象
静态代码块
获取当前进程根目录下的文件路径
也可以用getbundle来获取,但条件比较苛刻
三个点…表示多个变量
获取所有的public fileds
获取所有fileds
获取属性的修饰符和属性的名称和属性的类型
自定义注解
元注解
并且可以被反射
注解里面的变量声明时要加括号
注解赋值,只有一个变量时,赋值可以直接写,无需使用 变量=xxx 的形式