一些JavaSE学习过程中的思路整理(二)(主观性强,持续更新中...)
一些JavaSE学习过程中的思路整理(二)(主观性强,持续更新中...)
未经作者允许,不可转载,如有错误,欢迎指正o( ̄▽ ̄)o
将一个子类的引用对象赋值给超类的对象(多态)
- 赋予了子类对象的超类对象只能调用超类中定义的public成员变量和方法
- 如果子类重写了超类中的方法,就会调用子类中的方法(这里真的有点搞心态)
- 关于多态:具体使用有两种常见方式(核心原理都是将子类的对象赋值给超类的对象引用)
- 定义方法时形参类型为父亲,传入的类型为子类类型参数
- 定义方法时返回类型为父亲,实际调用时返回的类型子类对象
建议自己写个小的测试demo体会一下,下面是我的测试代码
public class Test1 {
public static void main(String[] args) {
VIP vip = new VIP();
SuperVIP superVIP = new SuperVIP();
Owner owner = new Owner();
//这里owner对象的custom成员变量所属的类是两个VIP类的超类
owner.setCustom(superVIP);
owner.settlement();
//custom本质上是一个SuperVIP的对象的引用
Custom custom = owner.getCustom();
//这里调用的是子类重写后的方法
custom.buyBook();
//这个num是父类的public成员变量,但是无法获取custom的私有成员变量
//private修饰的成员变量只能在同一个类中直接访问,通常用该类的public方法访问
System.out.println(custom.num);
//System.out.println(custom.getName());也无法获取子类的私有成员属性
SuperVIP superVIP1 = (SuperVIP) custom;
//之所以能强制类型转化是因为custom本质上就是SuperVIP对象引用
//所以说继承是多态的前提
System.out.println(superVIP1.getName());
}
}
class Custom {
private int money = 50;
public int num = 100;
public void buyBook() {
System.out.println("店主买书不花钱");
}
}
class VIP extends Custom {
public void buyBook() {
System.out.println("普通会员买书打八折");
}
}
class SuperVIP extends Custom {
private String name = "我是SVIP";
public void buyBook() {
System.out.println("超级会员买书打六折");
}
public String getName() {
return name;
}
}
class Owner {
private Custom custom;
public Custom getCustom() {
return custom;
}
public void setCustom(Custom custom) {
this.custom = custom;
}
public void settlement() {
custom.buyBook();
}
}
抽象方法和抽象类
- 抽象类中可以有普通方法,普通类中不能有抽象方法
- 当子类继承抽象父类,若子类不是抽象类,则要重写父类的所有抽象方法
简单概括以下包装器类的作用
对应8个基本数据类型有8个包装器类,这些类可以用于新建对应8个基本数据类型的对象,并且有着自动装箱,拆箱的功能(如:很多时候一些方法的参数时Obj类型的对象,但是我们直接传入基本数据类型的参数可以完成调用),在这些类中还定义了许多静态方法用于基本数据类型和包装器类之间的转换,这里感觉力扣上刷点题应该就会熟悉这些API了
面向接口编程时的一些细节
有一种说法:接口其实就是抽象类,极度抽象的抽象类,接口中不能存在非抽象方法,接口中的所有方法必须全部是抽象方法。在接口使用时有以下一些要求:
- 接口中成员变量只能定义public和默认访问权限修饰符
- 接口中的成员变量默认为static final类型,可以通过接口直接访问,同时不能修改值,必须在声明时完成初始化
- Java支持单继承,但是可以实现多个接口,这里就体现了接口的解耦合以及制定规范的作用
final关键字的功能
修饰一个方法:该方法可以被继承但无法被重写
修饰一个类:该类为最终类,无法被继承
修饰一个基本数据类型:该值为常量无法被修改
以byte类型为例解释计算机中以补码存储的细节
在八位二进制下,原码左侧第一位为符号位,除符号位外其余位取反为反码,反码+1为补码,计算机中以补码形式存储数据,其中要注意0的存储与-128的存储
- 0:由于以补码形式存储,0不分正负,这里将0000 0000作为0的补码
- -128:-128没有原码与反码,而原本“-0”的补码1000 0000用于表示-128的补码,这样就充分利用了每一个补码的表示
- 补码的意义:举个栗子,1按照0000 0001的补码存储,-1按照1111 1111的补码存储,-1+1 = 0 <=> 0000 0001 + 1111 1111,补码相加后溢出正好为0,符合-1+1 == 0的结果,这就正好自圆其说了
下面是一个byte型的1左移6位,7位,8位后的结果测试:
public class Test1 {
public static void main(String[] args) {
byte test = 1; test <<= 6;
System.out.println(test);
test = 1; test <<= 7;
System.out.println(test);
test = 1; test <<= 8;
System.out.println(test);
//以下两个是int左移7位和31位,这里是用于区分的,因为默认是int
System.out.println(1<<7);
System.out.println(1<<31);
}
}
异常类的分类&捕获与throw & throws的区分
异常类是一个树形的族谱结构,以下两个异常为Throwable类的两个子类
- Error:系统错误,程序无法处理
- Exception:程序运行时出现的错误,程序员可以处理()
try {
//可能会抛出异常的代码
} catch {
//对异常进行处理
} finally {
//一定会执行的代码
}
throws关键字的作用:
- throws作用于方法,修饰符 返回值类型 方法名(参数列表) throws Exception
- throw是写在逻辑处理过程中的代码,人为抛出异常
- 如果方法 throw 的是 RuntimeException 异常或者其子类,外部调用时可以不处理,JVM 会处理。
- 当人为抛出Exception对象(或者其子类异常对象时),我们必须处理这个异常对象(在本方法内对抛出的异常进行捕获操作),但是也可以选择自己不捕获,试图甩锅?这时可以用throws修饰这个方法,这样throws就会将异常对象抛出给方法的调用者处理(自己不处理给别人处理),此时方法的调用者就可以选择try-catch进行捕获,或者依旧将自己用throws修饰,继续甩锅?最终如果main方法不处理就会交给JVM处理(中断程序)
接下来时三种throws的使用情况
1.下面的代码是异常抛出方法本身不处理,并且调用者依旧选择不处理,将其交给JVM中断程序处理
public class Test1 {
public static void main(String[] args) throws Exception {
int[] array = {1, 2, 3};
//此时main方法中并未对这个抛出异常对象的方法进行捕获操作,选择交给JVM中断处理程序
test(array, -1);
}
public static void test(int[] array, int index) throws Exception {
if (index < 0 || index >= 3)
//这句抛出就必须处理这个异常对象,此时在方法后用throws相当于
//将这个抛出的异常交给方法的调用者main方法处理
throw new Exception("下标越界");
System.out.println(array[index]);
}
}
2.下面代码是test方法不处理,调用者main方法选择自己try-catch捕获抛出的异常,自己处理
public class Test1 {
public static void main(String[] args) {
int[] array = {1, 2, 3};
//此时方法调用者main选择捕获这个抛出异常的方法
try {
test(array, -1);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void test(int[] array, int index) throws Exception {
if (index < 0 || index >= 3)
//这句抛出就必须处理这个异常对象,此时在方法后用throws相当于
//将这个抛出的异常交给方法的调用者main方法处理
throw new Exception("下标越界");
System.out.println(array[index]);
}
}
3.下面的代码时test方法选择自己直接捕获自己抛出的异常,并进行处理
public class Test1 {
public static void main(String[] args) {
int[] array = {1, 2, 3};
test(array, -1);
}
public static void test(int[] array, int index) {
if (index < 0 || index >= 3)
//此时test本方法直接自己处理自己抛出的异常对象
try {
throw new Exception("下标越界");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(array[index]);
}
}
Java中开启线程的两种方式
- 通过继承Thread类,Thread类本身继承了Runnable接口,所以内部已经有了run方法,需要重写run方法为我们需要的业务逻辑代码,之后实例化Thread类的实例后调用start方法,而不是run方法(start方法包含了开启线程,等待资源分配,然后调用run方法的过程,直接调用run方法就是单线程的普通调用方法的过程)
- 通过实现Runnable接口,实现该接口的run方法为我们需要的业务逻辑,由于单单Runnable的实现类是没有开启线程的能力的,需要有Thread类的实例来开启线程。综上:利用Thread的构造函数,以Runnable接口的实现类为参数,声明初始化一个Thread类(要明确线程类是用于抢占CPU资源的,而抢占到资源后就会执行run方法中的任务,这里的Runnable接口的实现类就是run方法的承载者)
下面是一个例子实现了两种不同的开启线程的方式
public class Test1 {
public static void main(String[] args) {
//通过实现接口的方式可以解耦合
MyRunnable myRunnable = new MyRunnable();
//调用Thread类的构造函数传入线程需要执行的任务(业务逻辑)
Thread thread = new Thread(myRunnable);
//开启线程等待资源分配,然后执行run方法业务
thread.start();
//通过继承的方式
MyThread myThread = new MyThread();
myThread.start();
for (int i = 0; i < 1000; i++)
System.out.println("++++++++++主线程++++++++");
}
}
class MyRunnable implements Runnable {
//Runnable是一个接口,内部只有一个抽象的run方法(代表开启线程后需要执行的业务逻辑)
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("--------MyRunnable--------");
}
}
}
class MyThread extends Thread {
//通过继承Thread类的方式,由于Thread类本身就继承了Runnable接口
// 因此所创建的Thread类的实例内部有run方法
//这里是重写父类的run方法,替换为自己想要执行的任务
@Override
public void run() {
for (int i = 0; i < 1000; i++)
System.out.println("=========MyThread============");
}
}
线程的五种状态以及状态之间的转换
- 创建状态:实例化一个新的线程对象,还未启动
- 就绪状态:创建好的线程对象调用start方法完成启动,进入线程池等待抢占CPU资源
- 运行状态:线程对象获取了CPU资源,在一定的时间内执行任务
- 阻塞状态:正在运行的线程暂停执行任务,释放占用CPU的资源,并在解除阻塞态之后也不能直接回到运行状态,而是重新回到就绪状态,等待获取CPU资源
- 终止状态:线程运行完毕或者因为异常导致程序终止运行
创建——》就绪、就绪《——》运行、运行——》阻塞、阻塞——》就绪、运行——》终止
线程的调度:休眠&合并&礼让&中断
- 线程休眠:让当前线程暂停执行,从运行状态进入阻塞状态(相当于被挂起一定的时间,且还不允许回到就绪状态),将CPU资源释放,通过sleep()实现,sleep()是Thread类的静态本地方法,具体实现用c/c++,对于任何一个线程的实例对象来说(包括主线程),都可以使用Thread.sleep()的静态方法实现对当前线程的挂起,但如果该对象已经继承了Thread类,则可以直接打点调用sleep()方法
注意点:在外部调用时,sleep休眠要放在启动之前;否则就是在内部调用sleep则可以随时休眠,下面是一个小的例子
public class Test1 {
public static void main(String[] args) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//下面开启子线程的代码也是包含在main主线程中的,所以主线程挂起后
//下面的代码也无法继续执行
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 1000; i++)
System.out.println("-----MyRunnable------");
}
}
class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++)
System.out.println("++++++++MyThread+++++++++");
}
}
- 线程合并:线程甲和线程乙,线程甲执行到某个时间点的时候调用线程乙.join方法,则表示从当前时间点开始,CPU资源被线程乙独占,线程甲进入阻塞状态,直到线程乙执行完毕,线程甲进入就绪状态(相当于乙的执行结束时解除甲的阻塞状态的条件),等待获取CPU资源进入运行状态,并且也可以通过给join方法输入参数表示线程乙将独占CPU的时间(不输入参数则是始终独占直到乙线程执行结束)
这里我做了一个测试,如果由三个线程:主线程、甲线程、乙线程,在主线程中某个位置调用甲线程.join(),会使得除主线程外的另外两个线程继续争夺CPU的资源,直到甲结束,主线程才会回到就绪态去竞争CPU的使用权,如果此时乙线程还没有结束(我估计在测试代码中将乙线程的循环写的很长),则会继续与主线程进行CPU资源的竞争
public class Test1 {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
MyThread myThread = new MyThread();
myThread.start();
for (int i = 0; i < 100; i++) {
System.out.println(i + "========main========");
if (i == 50) {
try {
Thread.sleep(2000);
myThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 1000000; i++)
System.out.println(i + "-----MyRunnable------");
}
}
class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++)
System.out.println(i + "++++++++MyThread+++++++++");
}
}
线程礼让:yield是一个静态方法,通过调用该方法,是在某个特定的时间点让线程暂停抢占CPU资源的行为,只是暂时的礼让
线程中断:很多情况导致线程停止运行,如线程执行完毕自动停止,线程执行过程中遇到错误抛出异常并停止,或者线程执行过程中根据需求手动停止,有如下三个实例方法
- public void stop() 强行中断线程,不推荐使用
- public void interrupt() 中断当前线程
- public boolean isInterrupted() true表示已经中断,而false表示未中断(当然如果线程处于没有运行的就绪态那就称不上中断)
一些获取当前线程信息的实例方法:
- thread.setName("线程一") 为当前线程设置一个名称
- thread.getState() 获取当前线程的状态,是一个枚举类型
匿名内部类实现接口或者继承父类
new SuperType(construction parameters) {
inner class methods and data
}
其中,SuperType可以是接口,如果是这样,内部类就要实现这个接口,Super Type也可以是一个类,如果是这样,内部类就要扩展这个类。
一些JavaSE学习过程中的思路整理(二)(主观性强,持续更新中...)的更多相关文章
- 一些JavaSE学习过程中的思路整理(主观性强,持续更新中...)
目录 一些JavaSE学习过程中的思路整理(主观性强,持续更新中...) Java书写规范 IDEA的一些常用快捷键 Java类中作为成员变量的类 Java源文件中只能有一个public类 Java中 ...
- iOS --- 总结Objective-C中经常使用的宏定义(持续更新中)
将iOS开发中经常使用的宏定义整理例如以下,仅包括Objective-C. 而对于Swift,不能使用宏,则能够定义全局函数或者extension.请參考博客iOS - 总结Swift中经常使用的全局 ...
- 最简单的 IntelliJ IDEA 中使用 GitHub 进行版本控制教程(持续更新中)
一.在 IntelliJ IDEA 中新建一个项目并提交到 GitHub 1. 运行 IDEA,点击[Create New Project],在 IDEA 中新建一个项目. 2. 在选择项目类型对话框 ...
- java视频教程 Java自学视频整理(持续更新中...)
视频教程,马士兵java视频教程,java视频 1.Java基础视频 <张孝祥JAVA视频教程>完整版[RMVB](东西网) 历经5年锤炼(史上最适合初学者入门的Java基础视频)(传智播 ...
- 2020年腾讯实习生C++面试题&持续更新中(3)
2020年腾讯实习生C++面试题&持续更新中(3) hello,大家好,我是好好学习,天天编程的天天. 来给大家大家分享腾讯实习生面经了. 天天希望大家看到面经后一定要做充分的准备,结合自己掌 ...
- 2020年腾讯实习生C++面试题&持续更新中(1)
2020年腾讯实习生C++面试题&持续更新中(1) 腾讯面试整理(1) 最近大三的学生找实习生的同学非常多,给大家分享一篇腾讯实习生的面试题,关于面试题,会持续更新~~~ 也算是今天开通博客的 ...
- 中国.NET:各地微软技术俱乐部汇总(持续更新中...)
中国.NET:各地微软技术俱乐部汇总(持续更新中...) 本文是转载文,源地址: https://www.cnblogs.com/panchun/p/JLBList.html by 史记微软. ...
- html知识点汇总(持续更新中)
本人从事前端行业三年多,打算从今天开始整理一些关于前端的一些比较经典的知识点,持续更新中...希望能对一些相关知识点有疑问的朋友有一些帮助! HTML篇: 1.常见的行内元素/块级元素/空元素有哪些? ...
- EOS开发经验总结——不定期持续更新中
一.新手安装mysql乱码问题 1.数据库安装时设置默认编码格式为UTF8或者打开mysql安装目录下my.ini,变更default-character-set=utf8: 2.打开EOS的Gove ...
- fastadmin 后台管理框架使用技巧(持续更新中)
fastadmin 后台管理框架使用技巧(持续更新中) FastAdmin是一款基于ThinkPHP5+Bootstrap的极速后台开发框架,具体介绍,请查看文档,文档地址为:https://doc. ...
随机推荐
- .NET周刊【9月第4期 2023-09-24】
国内文章 有趣的"可扩展近似计数"算法 https://zhuanlan.zhihu.com/p/656817283 在编程的世界里看见数学的身影,会让我充满好奇和兴奋.这不,在一 ...
- 1111error
Allowed memo ry size of 268435456 bytes exhausted编辑的没有缓存都丢了
- Composite 组合模式简介与 C# 示例【结构型3】【设计模式来了_8】
〇.简介 1.什么是组合设计模式? 一句话解释: 针对树形结构的任意节点,都实现了同一接口,他们具有相同的操作,可以通过某一操作来遍历全部节点. 组合模式通过使用树形结构来组合对象,用来表示部分以 ...
- 惊奇!Android studio内部在调用Eclipse
现在用Android studio的人越来越多,主要是说谷歌不再支持Eclipse,而力推Android studio.但是as也太不给力了,我之前写过一篇博客提到. 今天要说的是一个惊天的消息,如题 ...
- Java文件与IO流
首先我们要清楚什么是流,正如其名,很形象,流就是像水一样的东西,具有方向性,在java中 ,流大概就是类 接下来,我们要对输入输出流有一个基本认识,什么是输入输出流呢? 输入输出明显需要一个参照,而这 ...
- 基于Echart的前端可视化
GitHub 上有许多关于低代码自助可视化的项目,前端使用 Vue 和 ECharts 的示例.以下是一些可能符合你要求的项目: DataV: 项目链接:DataV 描述:DataV 是一款基于 Vu ...
- 一元多项式求和(c++源码)
LinkList.h #ifndef LINKLIST_H_ #define LINKLIST_H_ #include<stdio.h> template<class T> s ...
- 【日常收支账本】【Day02】通过PyCharm集成QtDesigner和PyUIC快速创建界面
一.集成QtDesigner和PyUIC PyCharm集成QtDesigner和PyUIC教程 二.在QtDesigner中画出窗体 1. 主界面 编辑账本: 新增.修改或删除记录 可视化账本:通过 ...
- Git 行尾设置须知
1 背景 远端文件拉取到本地后,会根据本地机器的操作系统.或文件编辑器,修改文件内容的行尾.例如远端代码为适配其代码托管的宿主.存储服务器与编译构建环境,通常采用 LF 作为行尾,符合 Linux 文 ...
- goto关键词
1.前言 goto,一个蒟蒻一用就废,大佬一用就吊炸天的神奇关键字. 今天,我要来盘它!!! 2.goto只能在函数内实现跳转,不能跨函数跳转 因为标号label是局部有效的. #include &l ...