JAVASE
以下内容根据【尚硅谷】7天搞定Java基础,Java零基础极速入门 视频简单总结而成
所谓变量就是可以改变的向量存储;标识符即标识数据的符号——变量名:只有下划线和$,预定义关键字或保留字不给用
-
基本数据类型 byte 8,short 16,int,long 64, float f = 1.0F; 范围小的数据转换为大的没问题,但大到小需要
引用数据类型 类:对象是将内存地址赋值给了变量,所以变量其实是引用了内存中的对象,所以称之为引用变量
String,接口,数组,枚举,特殊类型值:null -
&与运算,&&短路与运算:会根据第一个条件表达式结果来判断是否执行第二个条件表达式
-
先声明类(声明属性和方法),创建对象(main里),再执行方法
-
属性无需初始化,在构造对象的时候JVM会帮助我们自动初始化0,0.0, false,“”,null
-
参数个数不确定(0-n),但类型相同时:参数类型… 参数名称;如 (String… name);可变参数声明在最后
-
压栈弹栈;而引用数据类型是传递内存地址,如User.name -
把与对象无关,只和类相关称之为静态;静态方法不可访问成员属性和方法,反之可以;类的信息加载完成后自动调用静态代码块{不用构建对象直接调用class名称即可,而普通代码块需要new一下才会执行}
-
java.lang包不用import;先package,再import; 构造方法构建对象,但构建对象后才会用它初始化,一般参数用于赋值
-
从类型角度来看,多个子类继承的是一个父类; 先构建父类对象(继承父类属性和方法开辟的内存空间,而不是真正的父类对象)再构建子类对象;父类有参构造需在子类构造方法中使用super(参数);
-
所谓的多态,其实就是一个对象在不同场景下表现出来的不同状态和形态; 多态语法其实就是对对象的使用场景进行约束:取决于声明对象自己
{子类继承了父类所有,在需要时可以当成父类来用 Person p1 = new Boy(); 但此时无法调用Boy自己的功能 } -
多态:一个类中,不能重复声明相同的方法和属性;但可以根据**参数列表(个数 顺序 类型)**来区分;构造方法亦可重载;在一个构造方法里可通过this调用其他的构造方法。
-
基本数据类型在匹配方法的时候,可以在数值不变的情况下,扩大数据的精度,比如byte b = 10; test(short b);
但Byte无法和char类型(16位)做转换,因为char没有负数,而byte存在负数
//子类没有该方法 会逐步调用BBB->AAA->Object -
方法重写要保证,子类和父类方法名相同,返回类型相同,参数列表相同(构造方法不行)
在10最后一句的基础上:一个对象能使用什么方法(CCC+DDD)/属性(i),取决于引用变量的类型 CCC ddd = new DDD();
但一个对象的方法的具体使用(直接间接)时需要看具体的对象的(有DDD用DDD,没就用CCC) CCC ddd = **new DDD();**但属性的具体使用不看具体对象,在哪声明在哪 用(默认有this.) -
Java源码中public类(公共任意使用)只能有一个,而且必须和源码文件相同;main方法是JVM调用,不考虑权限问题
private:同一个类中可以使用,声明对象不可调用;default即是JVM默认提供包(路径)权限,但在其他包下面无法调用;protected子类可以访问;
私有:同类,默认:同类同包(路径),受保护:同类,同包(路径),子类{自己父亲保护自己孩子,只能访问public class的Object,而不是新声明对象的Object}、
访问权限其实就是访问属性,方法的权力和限制 -
Java中不允许用private和protected声明外部类;内部类当成外部类的属性即可,所以需要构建外部类.内部类使用
-
单例模式:由于类的创建过程复杂,类的对象消耗资源
-
使用final修饰变量,数据初始化后不被修改{常量or不可变量};但修饰属性值,需要手动内部初始化或者使用构造函数中this.name=name来外部传参初始化;
也可修饰方法,但不可被子类重写(不可修饰构造方法:无意义,也可修饰方法参数,方法中不可修改);修饰类也行,但就没有子类了 -
分析问题: 对象(具体) ==> 类(抽象) ; 编写代码: 类(抽象) ==> 对象(具体); 抽象类{抽象方法无大括号,但也可以有非抽象方法} 因为不完整无法构建对象,只能被继承,通过子类间接构建对象,同时也需要重写抽象方法补充完整。
abstract不能和final同时使用(方法无法重写,类没有子类) -
接口可以简单理解为规则 interface 接口名称 {规则属性, 规则的行为} 其实是抽象的
规则的属性必须是静态 固定值,而且不能修改(和对象无关); 行为是抽象的,(由每个对象自行决定)。属性和行为的访问权限必须是公共的。
接口和类是两个层面上的东西。接口可以继承其他接口,类的对象需要遵循接口/实现(implements)多个接口。 -
枚举类包含的特定对象一般不会改变,全大写标识符,和后面语法用分号隔开。枚举类不能创建对象,它的对象是在内部自行创建
匿名类:在某些场合下,类的名字不那么重要,我们只想使用类中的方法或功能
-
编写逻辑用bean建立数据模型,属性私有化 set和get;如果属性和(局部)变量名称相同,访问时不加修饰会优先访问变量.Object可用的一些方法如下
-
数组
-
char[]和byte[]可直接传入String,但三个字节表示中文汉字,byte需要new String(bs,“UTF-8”)传入
StringBuilder
char[] chars = s6.toCharArray(); byte[] bytes = s6.getBytes("UTF-8");
StringBuilder s = new StringBuilder();
for(int j=0;j<100;j++) s.append(j);//效率高,底层用数组方式构建,而不是拼接
System.out.println(s.toString());
- 除了八个基本数据类型外还有引用数据类型(String Array),均继承Object,可以构建对象,调用属性和方法实现一些操作。因此,提供了八个与之对应的包装类 引用数据类型。
Byte b = null; Short s = null; Integer i = null; Long lon = null;
Float f = null; Double d = null; Character c = null; Boolean bln = null;
int i1 = 10;
Integer i2 = Integer.valueOf(i1);
Integer i3 = i1; //自动装箱
int i4 = i2.intValue();
int i5 = i2; //自动拆箱
i2.byteValue();i2.compareTo(i3);i2.doubleValue();
- 日期和日历
//日期类
Date date = new Date(); //日期格式不太好理解 Tue Feb 21 00:00:00 CST 2023
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); //yyyy-MM-dd HH:mm:ss.SSS
String dateFormatString = sdf.format(date); //转换成日期格式化的字符串
String dateString = "2023-02-21"; //注意 和上方new SimpleDateFormat()内格式相同
Date parseDate = sdf.parse(dateString); //String -> Date
date.setTime(System.currentTimeMillis()); //根据时间戳构建指定的日期对象
date.getTime(); //获取时间戳
parseDate.before(date); parseDate.after(date);// 解析的时间早/晚于date的时间则是true
//日历类
Calendar instance = Calendar.getInstance(); // 这是抽象类无法构建实例对象,用getInstance静态方法 --- 单例模式
instance.get(Calendar.YEAR);
instance.get(Calendar.MONTH); //月份从0开始
instance.get(Calendar.DAY_OF_MONTH); instance.get(Calendar.DAY_OF_WEEK);
instance.setTime(date); instance.setTime(new Date()); //传指定日期过来,改日历
instance.add(Calendar.YEAR,-1); //当前日历-1年
static void printCalendar(){ //打印日历
System.out.println("一\t二\t三\t四\t五\t六\t日");
//把日历对象设定为当前月的第一天
Calendar firstDate = Calendar.getInstance();
firstDate.set(Calendar.DAY_OF_MONTH,1);
int maxDay = firstDate.getActualMaximum(Calendar.DAY_OF_MONTH); //一个月最大天数
for (int i = 0; i < maxDay ; i++){
int weekX = firstDate.get(Calendar.DAY_OF_WEEK); //一周当中第几天;周日是1,周一是2..周六是7
int monthY = firstDate.get(Calendar.DAY_OF_MONTH); //一月当中第几天
if (i==0){ // 第一天,前面加\t,周日+6个
if (weekX == Calendar.SUNDAY){ //周日,轮转
for (int j = 0;j < 6;j++)
System.out.print("\t");
System.out.println(monthY);
}else {
for (int j = 0;j < weekX-2;j++)
System.out.print("\t");
System.out.print(monthY+"\t");
}
}else {
if (weekX == Calendar.SUNDAY){ //周日,轮转
System.out.println(monthY);
}else if(monthY == maxDay){
System.out.print(monthY+"\n");
} else{
System.out.print(monthY+"\t");
}
}
firstDate.add(Calendar.DATE,1);
}
}
- 工具类是公共静态且丰富的,在基本数据类型中,== 比较值,在引用数据类型则是比较变量内存地址,因此用.equals()更好,String会自动将 ==优化成比较值,但如果是new出来的和原来的则不等。类则需要重写equals方法{引用数据类型和包装类用equals}
int i = 10; double j = 10.0;
System.out.println(i==j); //true
String s1 = "abc"; String s2 = new String("abc");
System.out.println(s1 == s2); //false
User7 user1 = new User7();
User7 user2 = new User7();
System.out.println(user1 == user2); //false
System.out.println(user1.equals(user2)); //false ;继承父类的equals,其内核还是 双等号,除非重写
//包装类和引用数据类型都用equals
Integer i1 = 127; //默认在IntegerCache内(-128~127)可以相等,但超出cache会重新new一个
Integer i2 = Integer.valueOf(127);
System.out.println(i1 == i2);
System.out.println(i1.equals(i2));
- java异常分两类,一是可以通过代码恢复正常逻辑执行的异常,称为运行期异常: RuntimeException
二是不可以通过代码恢复正常逻辑执行的异常,称为编译期异常: Exception
try{ 封装所有异常并抛出 }catch(抛出的异常对象 对象引用){ 异常的解决方案}catch(){ 捕捉多异常,先抓小范围}finally{最终执行的代码逻辑}
如果方法中可能会出现问题,需要提前使用throws声明可能的异常;如果程序中需要手动抛出异常对象,那么需要使用throw关键字,然后new出新的(自定义)异常对象
===========================================================================================
以下属于进阶语法
- 对不确定的有关系的数据进行相同的逻辑处理的场合,使用集合是一个不错的选择
1.单一数据体系:Collection接口定义了相关的规则
2.成对数据体系:Map接口定义了相关的规则,2个数据有关系,即键值对
1.Collection接口
常用接口
List : 按照插入顺序保存数据,数据可重复
具体实现类:ArrayList ,LinedList
Set: 集,无序保存,数据不能重复
具体实现类:HashSet
Queue: 队列
具体实现类:ArrayBlockingQueue
2.Map接口
具体实现类: HashMap Hashtable - ArrayList = Array + List : 列表,清单 按照数据插入顺序进行存储; 集合内部按照数组进行存储
//ArrayList = Array + List : 列表,清单 按照数据插入顺序进行存储; 集合内部按照数组进行存储
ArrayList list = new ArrayList(2); //放小括号里ctrl+P提示创建方式 有三种 传递整形参数,不传参,传集合参数
// (1)传递整形参数:传int 用于设定底层数组长度
// (2)不传参: 直接new 底层数组为空数组
// (3)传集合参数: 传一个Collection集合类型的值,用于将其他集合中数据放在当前集合
list.add("zhangsan");
list.add(1,"lisi");//可以当插入用
list.add("zhangsan"); //自动扩容
System.out.println(list.get(2));
int i = 0;
while (i<list.size())
i++;
//TODO 修改数据 将指定位置的数据使用set方法修改,传递两个参数,一是表数据位置,二是修改的值,会返回修改前的值
Object modify = list.set(2,"wangwu");
System.out.println("修改前value "+modify);
//TODO 删除数据 传参1个
Object remove = list.remove(2);
System.out.println("删除的值:"+remove);
ArrayList arrayList = new ArrayList();
arrayList.add("1"); arrayList.add("1");
list.clear();
list.addAll(arrayList);
//TODO 循环遍历不关心集合数据的位置,可采用特殊for循环
// for(循环对象:集合)
for (Object obj: list){
System.out.println(obj);
}
// list.clear(); //删除全部
list.removeAll(arrayList); //删除指定集合所有数据
System.out.println(list.contains("zhangsan")+" "+list.indexOf("zhangsan")); //数据不存在返回-1,存在返回第一个
System.out.println(list.isEmpty());
list.toArray();
Object clone = list.clone(); ArrayList list1 = (ArrayList) clone; //复制新集合
- LinkedList = Linked(连接) + List
增加第一条数据,以及超出阈值时,LindedList快于ArrayList
增加非第一条数据,且不超出阈值时,ArrayList快
有索引时,ArrayList查找快;无索引时二者速度一致
LinkedList list = new LinkedList();
list.add("zs");
list.addFirst("ls");// == list.push("ls");
list.add(1,"ww");
list.set(1,"www"); // list.addAll(otherList); list.contains("ls");
list.remove("www"); list.remove();//默认删除第一个==list.pop(); list.remove(1);list.removeLast();
System.out.println(list.get(0)+" "+list.getLast());
System.out.println(list.element()); //获取第一个数据 list.lastIndexOf();
list.clear();
- 泛型 : 类似于多态对声明对象所能使用的方法进行限制。例如学生集合只能存放学生对象,不能放老师对象。约束存放在集合里的数据类型,取得时候就不是Object类,也不用强制类型转换了。
用于约束外部对象得使用场景叫做类型
用于约束内部对象得使用场景叫做泛型 可传参时定义类型参数
//泛型时规划内部的,可称之为类型参数
MyContainer<User07> myContainer = new MyContainer();
// myContainer.data = new Object(); //只能new User07
test(myContainer);//这会报错,因为泛型没有多态的用法,不能把父类的泛型 限制子类
public static void test(MyContainer<Object> myContainer){
System.out.println(myContainer);
}
- HashSet:第一个放进去不一定第一个取出来,无序但有确定的Hash计算,由于哈希冲突所以不会重复存放数据(除非链地址法)
31. Queue
ArrayBlockingQueue = Array Blocking (阻塞,堵住) + Queue
ArrayBlockingQueue queue = new ArrayBlockingQueue(3);
queue.add("ww"); queue.put("ls"); boolean t1 = queue.offer("zs");
queue.poll(); queue.take();
添加数据 add:超过3会报错Queue full;put:多了会阻塞一直运行; offer是比较好的方法,加超过阈值不会再增加也不报错
取数据 poll:取多了会取null值; take:取多了会一直等待
其余方法 如isEmpty等也存在
32. HashMap **
HashMap 为了解决查找慢的问题,提供了红黑二叉树**
//面向kv键值对,实现Map接口,底层也是数组+链表的hashset map版
HashMap<String, String> HashMap = new HashMap<>();
//添加修改均用put,会根据相同key,覆盖value
HashMap.put("zs","1"); HashMap.put("ls","1"); HashMap.put("ww","2");
System.out.println(HashMap.put("zs","3")); //覆盖的同时可以获得旧的值,如果是第一次put 返回值为null
System.out.println(HashMap.get("zs")+"\t"+HashMap);
HashMap.remove("zs"); HashMap.remove("ls","222");//第二个必须kv都相等才能删
HashMap.putIfAbsent("ww","4"); //有就添加,没就啥都不做
HashMap.replace("ww","4"); //真正的替换,没有该key值就返回null
Set set = HashMap.keySet();
Collection<String> values = HashMap.values();
System.out.println(set+":"+values);
HashMap.containsKey("ls"); HashMap.containsKey("1");
Set<Map.Entry<String, String>> entries = HashMap.entrySet();
for (Map.Entry<String, String> entry : entries) {
System.out.println(entry); //entry.getKey();entry.getValue()
}
- Hashtable 同步:安全,Hashmap异步快
//TODO 迭代器 获取在遍历时增加删除的数据,用for循环时只能修改数据,或者最后一次遍历时增删之前的数据 否则报错
Iterator<String> iterator = keys.iterator();
while (iterator.hasNext()) { //用于判断是否存在下一条数据
String key = iterator.next();
if(key.equals("b"))
iterator.remove(); //限定只能删除此时的key value
System.out.println(map.get(key));
}
- 集合框架工具类和常见问题
- File
//Unicode编码 组合过程叫做转码
// byte => -128~127 通过多个大于127的数字来组合表示中韩日文等:需要多个byte
// ascii => 0~127 常用字符 可用1个byte表示
public class IO02_Character {
//因此 改变数据的值不能直接在读取的data中修改
//简单可以用StringBuilder对象进行追加 => 由此推出了字节流对字符串进行操作
public static void main(String[] args) {
String filePath = "G:\\project\\AAA\\run.sh";
String filePath1 = "G:\\project\\backup\\sh.copy"; //自动生成sh.copy
File file = new File(filePath);
File desfile = new File(filePath1);
BufferedReader reader = null; //字节输入流;
PrintWriter writer = null; //字节输出流
StringBuilder ss = new StringBuilder();
try {
reader = new BufferedReader(new FileReader(file)); //需要传一个FileReader对象
writer = new PrintWriter(desfile);
String line = null;//读取文件中一行数据(字符串)
while((line=reader.readLine()) != null) {
writer.println(line); //写入每一行
// ss.append((char)data);
}
writer.flush(); //刷写数据 => 没装满也写入
// ss.append(" zhangsan");//之后将字符串数组转化为字节数组,再将数组中每一个字节写入到文件中
}catch (IOException e) { //可能会找不到该文件路径,因此放在try catch里
throw new RuntimeException(e);
} finally {
if (reader!=null){
try {
reader.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}if (writer!=null){
writer.close();
}
}
}
}
在Stream流中增加一个Buffer缓冲区
对象=>字节码文件(class) 序列化;反之则是反序列化
public class IO03_Object {
//序列化 & 反序列化 ; Object =》 byte文件
public static void main(String[] args) {
String filePath = "G:\\project\\AAA\\outObject.txt";
File file = new File(filePath);
boolean isWrite = false;
ObjectOutputStream objectOut = null; //对象输出流;
FileOutputStream out = null; //文件输出流
ObjectInputStream objectIn = null; //对象输入流;
FileInputStream in = null;
try {
User33 user = new User33();
if (isWrite){
out = new FileOutputStream(file);
objectOut = new ObjectOutputStream(out); //将Object写入到out的文件中
//Java中只有增加了特殊标记:接口,才能在写文件的时候自动序列化
objectOut.writeObject(user);
objectOut.flush();
}else {
in = new FileInputStream(file);
objectIn = new ObjectInputStream(in);
Object o = objectIn.readObject();
System.out.println((User33)o); //打印读取的对象
}
}catch (Exception e) { //可能会找不到该文件路径,因此放在try catch里
throw new RuntimeException(e);
} finally {
if (objectOut!=null){
try {
objectOut.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}if (out!=null){
try {
out.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}
class User33 implements Serializable{
}
IO常见异常使用Try Catch: FileNotFoundException(new FileInputStream)
IOException(in.read/close)
ClassNotFoundException(objIn.readObject)
NotSerializableException(objOut.writeObject)
35. 线程运行
36. 线程池
//线程池:线程对象的容器,在启动时可创建1至多个线程对象
//Java常见线程池有4钟
//(1)创建固定数量的线程对象
ExecutorService executorService1 = Executors.newFixedThreadPool(3);
//(2)根据需求数量动态创建线程;不够就创建新的,但旧有的做完了也会拿来用
ExecutorService executorService2 = Executors.newCachedThreadPool();
//(3) 单一线程 如果某个工作需要按顺序可以用
ExecutorService executorService3 = Executors.newSingleThreadExecutor();
//(4)定时调度线程:DelayedWorkQueue
ExecutorService executorService4 = Executors.newScheduledThreadPool(3);
for(int i = 0; i<5;i++){
executorService4.submit(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
}
-
线程同步
-
线程安全
所谓的线程安全问题,其实是在多线程并发执行时,修改了共享内存中共享对象的属性,导致的数据冲突(类似脏读)
-
反射基本操作
多态中父类无法调用子类的方法因此Parent par = New Child();时,会限制调用Child类的方法。
此时如果非要调用Child类的方法,需要借助反射 查看"镜中的自己"
Class<? extends User001> aClass = user.getClass();//类对象,对应Java中的Class文件
在cmd中输入以下命令,可查看字节码文件
javap -v Child(class名)
public class Reflect01_Class {
public static void main(String[] args) throws Exception{
User001 user = new Child001();
user.test1();
// user.test2();
Class<? extends User001> aClass = user.getClass();//类对象,对应Java中的Class文件
System.out.println(aClass.getSimpleName()); //获取类的名称 aClass.getPackageName()
aClass.getName(); //获取类的全名:包括包名
Class<?> superclass = aClass.getSuperclass(); //获取父类
System.out.println(superclass);
Class<?>[] interfaces = aClass.getInterfaces();//获取接口数组(可能多个)
//TODO 获取类的属性
Field f1 = aClass.getField("xxxx"); //根据属性名字获取类的public属性
Field f2 = aClass.getDeclaredField("xxxx"); //所有权限,包括private
Field[] declaredFields = aClass.getDeclaredFields(); //获取所有权限的所有属性
Field[] Fields = aClass.getFields(); //public也相同
//TODO 获取类的方法
Method m1 = aClass.getMethod("test2");
Method m2 = aClass.getDeclaredMethod("test1");
Method[] Methods = aClass.getMethods();
Method[] declaredMethods = aClass.getDeclaredMethods(); //同上
//TODO 构造方法
Constructor<? extends User001> constructor = aClass.getConstructor();
Constructor<?>[] constructors = aClass.getConstructors();
aClass.getDeclaredConstructor();
//TODO 获取权限(修饰符public等):方法权限,类权限,等:多个修饰符合成一个int
int modifiers = aClass.getModifiers();
boolean aPrivate = Modifier.isPrivate(modifiers);//通过布尔值判断,其余也一样
}
}
class User001{
public void test1(){
System.out.println("test1...");
}
}
class Child001 extends User001{
public void test2(){
System.out.println("test2...");
}
}
- 反射类加载器
public class Reflect02_ClassLoader {
public static void main(String[] args) {
//Java类分为3钟 同理,类加载器也分3钟
//1.Java核心类库中的类:String,Object
//2. JVM 软件平台开发商 (java -version可以看到 Java HotSpot)
//3. 自己写的类 User, Childer
//(1)BootClassLoader:启动类加载器:Java核心类库
//(2)PlatformClassLoader:平台类加载器 JVM平台等
//(3)AppClassLoader:应用类加载器; (1)>(2)>(3)
//TODO 获取类的信息
Class<Student> studentClass = Student.class;
ClassLoader classLoader = studentClass.getClassLoader();
System.out.println(classLoader);//获取类的加载器信息 App
System.out.println(classLoader.getParent());//获取平台类加载器信息
System.out.println(classLoader.getParent().getParent());//获取启动类加载器
Class<String> stringClass = String.class;
System.out.println(stringClass.getClassLoader()); //null,因为启动类加载器是通过os平台实现,而不是java实现,不然会有前后冲突
}
}
class Student{
}
练习以及常见异常
public class Reflect03_Test {
public static void main(String[] args) throws Exception {
//TODO 反射 练习 员工登录 与 常见异常
//1.ClassNotFoundException 构建方法对象 第三种方法会导致没有类异常
//2.NoSuchMethodException 没有方法异常<=getDeclaredConstructor
//3.IllegalArgumentException 参数传递异常<=newInstance
//4.NoSuchFieldException 没有属性异常<=getField
//5.IllegalAccessException 权限异常 没权限还访问<=set
//6.InvocationTargetException 调用目标异常 <=invoke
//构建方法对象
Class<Emp3> emp3Class = Emp3.class; //不new,采用反射构建方法对象
Class<? extends Emp3> emp3Class2 = new Emp3().getClass(); //第二种方法
Class<?> emp3Class3 = Class.forName("src.chapter05.Emp3");//或者采用全路径构建方法对象
Constructor<Emp3> declaredConstructor = emp3Class.getDeclaredConstructor();
//构建对象
Emp3 emp3 = declaredConstructor.newInstance();
//构建属性并赋值
Field account = emp3Class.getField("account");
Field password = emp3Class.getField("password");
account.set(emp3,"zhangsan");
password.set(emp3,"luoxiang");
//获取登录方法并调用
Method login = emp3Class.getMethod("login");
Object result = login.invoke(emp3);//调用方法并接收结果
System.out.println(result);
}
}
class Emp3{
public String account;
public String password;
public boolean login(){
if("admin".equals(account) && "admin".equals(password))
return true;
else
return false;
}
}