[TOC]
菜鸟教程学习笔记菜鸟教程
常用五大包:java.long(longuage)该包下的类,在使用时是不需要导包的;java.util 工具包;java,io 文件读写;java.net 网络编程包;java.sql 操作数据库
六种数字类型(四个整数类型,两个浮点类型),一个字符类型,一种布尔类型
类型 | 范围 | 包装类 | 字节数 |
---|---|---|---|
byte | 二的7次方 -128-127(默认值是0) | 1 | |
short | 二的15次方 -215~215-1 (默认值是0) | 2 | |
int | 二的31次方 -231 ~231-1(默认值是0) | Integer | 4 |
long | 二的63次方 -263~263-1(默认值是0L) | 8 | |
BigInteger | 大整数 | ||
float | 32位,最多表示8位小数; | 4 | |
double | 64位,最多表示16位小数 | 8 | |
BigDecimal | 大小数 | ||
boolean | 占一个字节,默认值是false | 1 | |
char | 16位 (默认值是’u0000’ String的值是null) | Character | 2 |
取值范围:byte<short<int<long<float<double
对于引用数据类型给变量存储的数据大多数都是一个地址值
大范围往小范围—>强制转换
小范围往大范围—->自然转换
修饰符 | 权限 |
---|---|
default | 在同一个包内可见,不适用任何修饰符,使用对象:类、接口、变量、方法 |
private | 在同一类内可见,使用对象:变量,方法。不能修饰类(外部类) |
public | 对所有的类都可见,使用对象:变量,接口,变量,方法 |
protected | 对同一包内的类的所有子类可见。使用对象:变量、方法。不能修饰类(外部类) |
静态的,属于类
static 不能直接修饰,只能取修饰成员方法,成员属性
被static修饰的成员变量属于类,不属于这个类的某个对象(多个对象共享一个static修饰的成员变量)
变量一旦被赋值之后,就不能更改,必须显式指定初始值
父类中的 final 方法可以被子类继承,但是不能被子类重写。
抽象类;抽象类不能用来实例化对象,声明抽象类的唯一目的是为了将来对该类进行扩充一个类不能同时别abstract和final修饰
public abstract class 类名{}
public abstract 返回值类型 方法名(参数);
抽象方法
抽象方法是一种没有任何实现的方法,该方法的具体实现由子类提供。
任何继承抽象类的子类必须实现父类的所有抽象方法,除非该子类也是抽象类。
如果该类有多个抽象方法,那么这个类就必须声明为抽象类,抽象类可以不包含抽象方法
synchronized修饰符声明的方法同一时间只能被一个线程访问 例:
public synchronized void showDetails(){
}
这种修饰的变量,只能活跃在内存中,不能用于持久化存储
序列化的对象被transient修饰的实例变量时,Java虚拟机跳过该铁定的变量
当然,如果一个用户有一些敏感信息(譬如密码,银行卡号等),为了安全起见,不希望在网络操作(主要涉及到序列化操作,本地序列化缓存也适用)中被传输。这些信息对应的变量就可以被定义为transient类型。换句话说,这个字段的生命周期仅存于调用者的内存中。
public transient int limit=55;//不能持久化
public int limit_int=55;//能持久化
volatile修饰符修饰的成员变量,在每次被线程访问时,都强制从共享存储中重新读取该成员变量的值,而且,当成员变发生变化时,会强制线程将变化值回写到共享内存中,在任何时刻,两个线程总是能看到某个成员变量的值是同一个值
= ——>赋值
== ——>相等判断(不比较前后值的数据类型,只比较值内容的是否相等)
对于基本数据类型,比较内容是否相等
对于引用数据类型,比较地址值是否相等
=== ——>相等判断(首先比较值的数据类型是否一致,再次比较值的内容是否相等)
== != > < >= <=
&& & || | !
&& 前面是假就不运算了后边的了,&是运算前后的得出结论;同理|| |也一样
int a=(条件)? value is true: value id false
该运算符用于操作对象实例,检查该对象是否是一个特定类型(类类型或接口类型)。
Mash类的指数,对数,平方根,三角函数。
Java Number & Math 类 | 菜鸟教程 (runoob.com)
方法:
int a=10,b=-5,c=10;
double d=1.2,e=-1.6;
String str="20";
System.out.println(Math.abs(b));
System.out.println("ceil:大于等于最小整数;的使用前面是1.2后面是-1.6"+Math.ceil(d)+"||"+Math.ceil(e));
System.out.println("floor:小于等于最大整数;的使用前面是1.2后面是-1.6"+Math.floor(d)+"||"+Math.floor(e));
System.out.println("rint:返回参数最接近的整数;的使用前面是1.2后面是-1.6"+Math.rint(d)+"||"+Math.rint(e));
System.out.println("round:四舍五入;算法是Math.floor(x+0.5);前面是1.2后面是-1.6"+Math.round(d)+"||"+Math.round(e));
System.out.println("min的使用"+Math.min(a,b));
System.out.println("max的使用"+Math.max(a,b));
System.out.println("exp:e的几次幂的使用"+Math.exp(1));
System.out.println("log:e的对数lnX的使用"+Math.log(Math.exp(1)));//
System.out.println("pow:a的b次方"+Math.pow(a,b));
System.out.println("sqrt:求算是平方根"+Math.sqrt(25));
System.out.println("sin"+Math.sin(Math.PI/2));
System.out.println("asin"+Math.sin(1));
System.out.println("其余三角函数也是一样的");
System.out.println("toDegrees将参数转换位角度"+Math.toDegrees(Math.PI/2));
System.out.println("toRadians将角度转化为弧度"+Math.toRadians(90));
System.out.println("random取随机数"+Math.random());
BigInteger
大数据的加add、减subtract、乘mutiply、除divide;
BigDecimal (有些时候操作小数会出现精度问题 例:System.out.println(0.09+0.01);//0.09999999999999999)
大小数的加减乘除和大数的加减乘除是一样的;
byte[] bys=new byte[]{97,98,99,100};
String str2=new String(bys);
String str3=new String(bys,1,3);//前面是用来设置开始的位置的,后面是设置列表中的总长度的
System.out.println(str2);//abcd
System.out.println(str3);//bcd
//解决请求乱码是需要用到,在此先做了解
String str4=new String(str3.getBytes("ISO8859-1"),"utf-8");
String str="abcde";
char[] chs=str.toCharArray();
byte[] bytes=str.getBytes();
System.out.println("转化为char列表"+ Arrays.toString(chs) +"转化为字节"+ Arrays.toString(bytes));
String str5="Abcde";
//equals和equalsIgnoreCase的区别:equals比较内容,并且区分大小写,equalsIgnoreCase只比较内容,不区分大小写
System.out.println("equals||"+str.equals(str5)+"||eqaulsIgnoreCase||"+str.equalsIgnoreCase(str5));
String s1="userlyz";
String s2="userlyz";
String s3=s1;
String s4=new String("userlyz");
String s5=new String("userlyz");
char[] helloArray={'u','s','e','r','l','y','z'};
String helloString=new String(helloArray);
System.out.println("我的名字是".concat("userlyz"));
System.out.println("普通+号连接符");
String fs;
fs=String.format("%f,%d,%s",1.2,123,"Str");
System.out.println(fs);
System.out.println("输出此字符串的哈希值"+"userlyz".hashCode());
System.out.println("indexOf:返回指定字符第一次出现的索引,默认开始位置是0"+"useruser".indexOf('s')+"||"+"useruser".indexOf('s',2));
System.out.println("indexOf:中间指定的参数,也可以是字符串"+"useruser".indexOf("er")+"||"+"useruser".indexOf("er",4));
System.out.println("与之还有lastIndexOf指定字符最后一次出现的位置,他也是可以指定开始位置的"+"useruser".lastIndexOf("er"));
System.out.println("length:字符串长度"+"useruser".length());
System.out.println("matches(String regex)判断此字符串是否匹配给定的正则表达式"+"useruser".matches(""));
System.out.println("代替 replace(char oldchar,char newchar):用newchar代替所有出现的oldchar"+"useruser".replace('s','a'));
System.out.println("replaceAll(String regex,String replacement):用replacement代替所有符合正则表达式regex的字符"+"useruser".replaceAll("","lyz"));
System.out.println("replaceFirst(String argex,String replacement):用replacement代替第一个符合正则表达式的字符串"+"useruser".replaceFirst("","lyz"));
System.out.println("拆分 split:按照给定的正则表达式进行拆分,第二个是用来限制拆分"+"user,u,s,er".split(",",2)[0]+"|||"+"user,u,s,er".split(",",2)[1]+"||"+"user,u,s,er".split(",")[3]);
System.out.println("判断是否是指定前缀 startwith(String prefix,int toffset)"+"useruser".startsWith("us")+"||"+"useruser".startsWith("us",2));
System.out.println("substring(int beginIndex,int endIndex)"+"useruser".substring(3)+"||"+"useruser".substring(3,5));
System.out.println("toCharArray() 转换位新的字符数组"+"useruser".toCharArray()[7]);
System.out.println("toLowerCase() 转换成小写"+"USERLYZ".toLowerCase());
System.out.println("toUpperCase() 转换成大学"+"userlyz".toUpperCase());
System.out.println("trim()忽略前面空格和后面空格"+" user ".trim()+"|");
System.out.println("isEmpty() 判断字符串是否为空");
StringBuilder类与StringBuffer之间的最大不同就在于StringBuilder的方法不是线程安全的(不能同步访问)
StringBuffer可将缓冲区安全的应用于多个线程,可以在必要时对这些方法进行同步
StringBuilder类相较于StringBuffer有速度优势,所以大多数情况下建议使用
append reverse delete insert replace
StringBuilder sb=new StringBuilder(10);
sb.append("userlyz..");
System.out.println(sb);
sb.append("?");//添加
System.out.println(sb);
sb.insert(8,"java");//插入
System.out.println(sb);
sb.delete(5,8);//删除
System.out.println(sb);
System.out.println("reverse() 字符串反转"+sb.reverse());
sb.replace(1,4,"lyz");//替换
System.out.println("替换之后的sb|"+sb);
sb.setCharAt(6,'Z');
System.out.println("设置索引处的字符设置"+sb);
sb.setLength(8);
System.out.println("修改长度之后|"+sb);
StringBuffer sf=new StringBuffer();
sf= (StringBuffer) sb.subSequence(1,4);
System.out.println("创建新的字符序列,为原序列的子序列"+sf);
String str=sb.substring(2,5);
System.out.println("返回一个新的String,可以只有开始值"+str);
indexOf() lastIndexOf() length() setCharAt(int index ,char ch)
一维数组 datatype[]q list=new datatype[arraySize]
多维数组 String[][] strs=new String[3][4];
double[] mylist={1.2,2.2,3.4,3.5};
double[] mylist_2={2.2,1.2,3.4,3.5};
List<Double> mylist_3=new ArrayList<>();
mylist_3.add(5.9);
mylist_3.add(6.7);
mylist_3.add(1.4);
for (double item :mylist){
System.out.println(item);
}
System.out.println("equals的使用,只有当两个数组的顺序和内容都一样"+mylist.equals(mylist_2));
Collections.sort(mylist_3);
System.out.println("升序排列之后的mylist_3:"+mylist_3);
binarySearch(Object[] a,Object key) 用二分查找在给定数组中搜索给定值对象。数组在调用之前必须排好序;有则返回索引,没有则返回-1
equals() 两个数组以相同的顺序,相同的元素,则这两个数组是相等的
sort() 根据元素的自然顺序进行升序排序
/*
日期时间
Date()
Date(long millisec)该参数是从1970年1月1日起的毫秒数
*/
Date mydate=new Date();
System.out.println("toString:显示日期和时间"+mydate.toString());
System.out.println("before after equals的使用:"+
new Date(99,1,12).before(new Date(99,2,18))+"||"+
new Date(99,1,12).after(new Date(99,2,18))+"||"+
new Date(99,1,12).equals(new Date(99,2,18)));
SimpleDateFormat ft=new SimpleDateFormat("GG yyyy-MM-dd hh:mm:ss SS E 一年中的第几周w 一个月中的第几周 W ");
System.out.println("SimpleDateFormat: 格式化日期 当前日期是"+ft.format(mydate));
//日期与毫秒的转换
Date date=new Date();
long time=data.getTime();
System.out.println("1970年1月1日以来的毫秒数"+time);
//获取当前的时间距1970年1月1日以来的毫秒值 long start = System.currentTimeMillis( );
//转换位日期对象
Date change_C_D=c.getTime();
System.out.println("转换之后的"+change_C_D);
获取当前的时间距1970年1月1日以来的毫秒值 long start = System.currentTimeMillis( );
使用printf格式化日期
// 初始化 Date 对象
Date date = new Date();
//c的使用 输出结果 星期一 七月 04 10:15:35 CST 2022
System.out.printf("全部日期和时间信息:%tc%n",date);
//F的使用 输出结果2022-07-04
System.out.printf("年-月-日格式:%tF%n",date);
//D的使用 输出结果07/04/22
System.out.printf("月/日/年格式:%tD%n",date);
//r的使用 输出结果10:15:35 上午
System.out.printf("HH:MM:SS PM格式(12时制):%tr%n",date);
//T的使用 输出结果10:15:35
System.out.printf("HH:MM:SS格式(24时制):%tT%n",date);
//R的使用 输出结果10:15
System.out.printf("HH:MM格式(24时制):%tR",date);
Date和String之间的转换
Date D_S_date = new Date(12354356000000L);
DateFormat D_S_df = new SimpleDateFormat("yyyy年MM月dd日");
String str = D_S_df.format(D_S_date);
System.out.println("转换之后的String"+D_S_date);//转换之后的StringFri Jun 30 13:33:20 CST 2361
String str_de = "2020年12月11日";
DateFormat S_D_df = new SimpleDateFormat("yyyy年MM月dd日");
Date S_D_date = S_D_df.parse(str);
System.out.println("转换之后的Date"+S_D_date);//转换之后的DateFri Jun 30 00:00:00 CST 2361
Calendar类是一个抽象类,在实际使用时实现特定的子类对象,创建对象过程中只需要使用getInstance方法创建即可
Calendar c=Calendar.getInstance();//默认是当前日期
System.out.println("默认是当前日期"+c);
c.set(2001,5,9);
System.out.println("设置的日期"+c);
Calendar c=Calendar.getInstance();
System.out.println(c.get(Calendar.DATE));
System.out.println(c.get(Calendar.HOUR_OF_DAY));
c.add(Calendar.DATE,-3);
c.set(Calendar.DATE,-3);
System.out.println(c.get(Calendar.DATE));
Date date=c.getTime();//Calendar转换
System.out.println(date);
实现了公历日期
字符 | 说明 |
---|---|
\ | 将下一个字符标记为特殊字符,文本,反向引用或八进制转义符;如n匹配n。\n匹配换行符 |
^ | 匹配输入字符串开始的位置 |
$ | 匹配输入字符串结尾的位置 |
* | 零次或者多次匹配前面的字符或者表达式;例:zo*匹配z,zo,zoo… |
+ | 一次或者多次匹配前面的字符或者表达式;例:zo+匹配zo,zoo…. |
? | 零次或者一次匹配前面的字符或者表达式;例:do(es)?匹配do,does |
{n} | 匹配n次 例:o{2}可以匹配food但是不能匹配Bob |
{n,} | 至少匹配n次 例:o{n,}不匹配Bob中的o,可以匹配foooood所有的o |
{n,m} | 至少n次,至多m次 |
? | 当 ? 紧跟任何其他限定符(*,+,?,{n},{n,},{n,m}),之后匹配模式是非贪心的;搜索尽可能短的字符串;默认贪心模式,匹配尽可能长的字符串;例:”oooo” ,”o+?”只匹配单个o,而”o+”匹配所有的”o” |
. | 匹配除了”\r\n”之外的任何单字符。若要匹配”\r\n”之内的任意字符使用”[\s\S]”之类的模式 |
(pattern) | 匹配pattern并捕获子表达式 |
(?:pattern) | 匹配pattern但不捕获子表达式 |
(?=pattern) | 执行正向预测先行搜索的子表达式 |
(?!pattern) | 执行反向预测先行搜索的子表达式 |
x|y | 匹配x或y |
[xyz] | 字符集,匹配包含的任一字符 |
[^xyz] | 反向字符集,匹配未包含的任何字符集 |
[a-z] | 字符范围,匹配指定范围内的任何字符 |
[^a-z] | 反向范围字符,匹配不在指定范围的任何字符 |
\b | 匹配一个字边界,即字与空格的位置 例:”er\b”匹配”never”中的”er”,但是不匹配”verb”中的”er” |
\B | 非字边界匹配 例:”er\b”匹配”verb”中的”er”,但是不匹配”never”中的”er”匹配”verb”中的”er” |
\cx | 匹配x指示的控制字符。例:\cM匹配Control_M或者回车符。x的值必须在A-Z或a-z之间 |
类的方法
Java 正则表达式 | 菜鸟教程 (runoob.com)
Pattern p1=Pattern.compile("dog");
Matcher m1=p1.matcher("dog dog dog ddogdddogg");
String output=m1.replaceAll("cat");
System.out.println(output);
方法不能嵌套,在方法内部声明变量或者参数,修饰符只能使用final,不能使用其他修饰符
方法只能是并列关系,声明的方法应该在类中,方法的外边
一个方法只能指定一个可变参数,他必须是方法的最后一个参数
public static void main(String[] args) {
printMax(34,3,3,2,56.5);
printMax(new double[]{1,4,2});
printMax();
}
public static void printMax(double... numbers){
if(numbers.length==0){
System.out.println("您没有提交参数");
return;
}
double result=numbers[0];
for(double item:numbers){
if(item>result){
result=item;
}
}
System.out.println("参数序列中最大值是"+result);
}
在对象被垃圾收集器回收之前调用,他用来清除回收对象
protected void finalize() throws java.long.Throwable
{
// 在这里终结代码
}
char c;
// 使用 System.in 创建 BufferedReader
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("输入字符, 按下 'q' 键退出。");
// 读取字符
do {
c = (char) br.read();
System.out.println(c);
} while (c != 'q');
next()和nextLine()的区别
next:一定要读取到有效字符之后才可以结束输入。对输入有效字符之前的空白next()方法可以自动将其去掉
只有输入有效字符之后输入的空格作为分隔符或者结束符next()不能得到带有空格的字符串
nextLine():以Enter为结束符,也就是说nextLine()方法返回的是输入回车之前的所有字符
nextLine()可以获得空白
异常通常有以下几大类:
1、用户输入非法数据
2、打开的文件不存在
3、网络通信时连接中断,或者JVM内存溢出
java异常处理是如何工作的:
1、检查性异常:最具代表性的异常错误是用户错误或者问题引起的异常,是程序员无法预见的
2、运行时异常:是可能被程序员避免的异。与检查性异常相反,运行是异常可以在编译时被忽略
3、错误:错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如当栈溢出时,一个错误就发上了,他们在编译过程中也检查不到。
try{
//程序代码
}catch(ExceptionName e1){
//catch代码块
}
//-------------------多重捕获块
try{
//程序代码
}catch(异常类型1 异常变量1){
//异常类型1之后执行的代码块
}catch(异常类型2 异常类型2){
//异常类型2之后的代码块
}...
例
try {
file = new FileInputStream(fileName);
x = (byte) file.read();
} catch(FileNotFoundException f) { // Not valid!
f.printStackTrace();
return -1;
} catch(IOException i) {
i.printStackTrace();
return -1;
}
public void deposit(double amount) throws RemoteEXception,InsufficientFundsException
{
// Method implementation 可以有一个异常,也可以有多个异常
}
无论是否发生异常,finally代码块中的代码总会被执行
try{
}catch(异常类型1 异常变量1){
}finally{
//程序代码
}
JDK7之后,Java新增try-with-resureces语法来打开资源,并且可以在语句执行完毕后确保每一个资源都被自动关闭
try(resources declaration){
//代码块
}catch(EXceptionType e1){
//异常块
}
//-----------例子
String line;
try(BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
while ((line = br.readLine()) != null) {
System.out.println("Line =>"+line);
}
} catch (IOException e) {
System.out.println("IOException in try block =>" + e.getMessage());
}
try-with-resources语句中可以声明多个资源,方法是使用分号;分隔各个资源
try(Scanner scanner=new Scanner(new File("textRead.txt"));PrintWriter writer=new PrintWriter(new File("textWrite.txt"))){
while(scanner.hasNext()){
writer.print(scanner.nextLine());
}
}
class MyException extends Exception{
//
}
例:package day_7_4;
import java.io.*;
import java.util.Scanner;
public class demo_error {
public static void main(String[] args) {
CheckingAccount c=new CheckingAccount(101);
System.out.println("Depositing $500...");//输入存入
c.deposit(500);
try{
System.out.println("\nWithdrawing$100...");
c.withdraw(100);
System.out.println("\nWithDrawing$600...");
c.withdraw(600);
} catch (InsufficientFundsException e) {
System.out.println("Sorry, but you are short$"+e.getAmount());
//throw new RuntimeException(e);
e.printStackTrace();
}
}
}
class InsufficientFundsException extends Exception{
private double amount;
public InsufficientFundsException(double amount){
this.amount=amount;
}
public double getAmount(){
return amount;
}
}
class CheckingAccount
{
//balance为余额,number为卡号
private double balance;
private int number;
public CheckingAccount(int number)
{
this.number = number;
}
//方法:存钱
public void deposit(double amount)
{
balance += amount;
}
//方法:取钱
public void withdraw(double amount) throws InsufficientFundsException
{
if(amount <= balance)
{
balance -= amount;
}
else
{
double needs = amount - balance;
throw new InsufficientFundsException(needs);
}
}
//方法:返回余额
public double getBalance()
{
return balance;
}
//方法:返回卡号
public int getNumber()
{
return number;
}
}
JVM(java虚拟机)异常:由JVM抛出的异常或错误。例如:NullPointerException类,ArrayIndexOutOfBoundsException类,ClassCastException类
程序级异常:由程序或者API程序抛出的异常。例如IIIegalArgumentException类,iiiegalStateException类
面向对象程序设计(OOP Object Oriented Programming)是目前主流的程序设计架构,使我们编程过程更符合人们的生活习惯
三大特性:封装、继承、多态
类:本质上就是一个功能集合;把一些有相同或者相似的一些功能集中放到一个地方(单元)—->类
类是项目或者工程的最小的组成单元
对象:开发思路:通过对象来帮助你完成一些事情;对象在实际中也是作为容器来使用的;
属性:对象当中共同存在的属性
子类拥有父类非private的属性和方法;子类可以拥有自己的属性和方法,即子类对于父类的拓展;子类可以用自己的方式实现父类的方法;Java是单继承,但是可以多重继承单继承是1v1,多重继承是B继承A,C继承B;提高类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)
继承可以使用extend和implement这两个关键词来实现继承,所有的类都默认继承于Object
extend一般用于继承普通类和抽象类;implement用来继承接口类
在java中,类的继承是单继承,extend只能继承一个类;
class Person{}
class Student extends Person{}
可以变相的使Java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口
public interface A{
public void eat();
public void sleep();
}
public interface B{
public void show();
}
public class C implements A,B{
}
super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类
this关键字:指向自己的引用;
在静态环境中不能使用super和this,具体看笔记4
final可以用来修饰变量(包括类属性,对象属性,局部变量,形参),方法(包括类方法,对象方法)和类
使用final关键字声明类,就是把类定义为最终类,不能被继承,或者用于修饰方法,该方法不能被子类重写:
子类是不继承父类的构造器(构造方法或者构造函数),他只是调用(显式或者隐式),如果父类的构造器带有参数,就必须在子类的构造器中显式地通过super关键字调用父类的构造器并配以适当的参数列表;如果父类构造器没有参数,则子类的构造器中不需要使用super关键字调用父类构造器,系统会自动调用父类的无参构造器
出现的位置:方法重写发生在父子类当中;方法重载发生在同一个类当中
判定机制:方法重载是根据参数列表进行判定;方法重写是根据
重载是一个编译期概念,重写是一个运行期的概念
子类对于父类允许访问的方法的实现过程进行重新编写,返回值和形参都不能改变,外壳不变,核心重写
重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常
例如: 父类的一个方法申明了一个检查异常 IOException,但是在重写这个方法的时候不能抛出 Exception 异常,因为 Exception 是 IOException 的父类
1、参数列表必须完全相同
2、返回类型可以不相同,但是必须是父类返回值的派生类
3、访问权限不能比父类中访问权限更低
4、父类只能被他的子类重写
5、声明final方法不能被重写
6、声明static的方法不能被重写,但是能被再次声明
7、子类和父类在同一个包下,子类可以重写父类的所有方法除了 private 和final方法
8、子类和父类不在同一个包中,子类只能重写 public 和protected的非final方法
9、重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
10、构造方法不能被重写
11、如果不能继承一个类,则不能重写该类的方法
Super可以调用父类的方法
class Person{
public void study(){
System.out.println("父类的学习");
}
}
class Student extends Person{
//父类若有study方法就重写,如果没有就报错
@Override
public void study() {
super.study();
}
}
在一个类里边,方法名相同,而形参不同,返回类型可以相同也可以不同
每一个重载的方法都有独一无二的参数类型列表;最常用的就是重载器的重载
1、被重载的方法必须改变参数列表(参数个数或参数类型不一样)
2、被重载的方法可以改变返回类型
3、可以改变访问修饰符
4、可以声明新的或者更广的检查异常
5、方法能够在同一个类或者子类中被重载
6、无法以返回值作为重载函数的区分
多态是同一个行为具有多个不同表现形式或形态的能力
多态就是同一个接口,按照不同实例而执行的不同操作
特点
对于成员方法:编译看左边,运行看右边
对于成员变量:编译看左边,运行看左边
1、消除类型之间的耦合关系;2、可替换性;3、可扩充性;4、接口性;5、灵活性;6、简化性;
1、继承;2、重写;3、父类引用指向子类对象(例:Animal a = new Cat();)
使用多态调用方法时,首先检查父类是否有该方法,如果没有,则编译错误,如果有再去调用子类的同名方法
public static void main(String[] args) {
Animal a = new Cat(); // 向上转型 父类指向子类
a.eat(); // 调用的是 Cat 的 eat
Cat c = (Cat) a;//向下转型
c.work(); // 调用的是 Cat 的 work
}
public static void show(Animal a) {
a.eat();
// 类型判断
if (a instanceof Cat) { // 猫做的事情
Cat c = (Cat)a;
c.work();
} else if (a instanceof Dog) { // 狗做的事情
Dog c = (Dog)a;
c.work();
}
}
//----------------接口环境和普通类环境都是可以的,这个实例是接口环境-----
abstract class Animal {
abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
public void work() {
System.out.println("抓老鼠");
}
}
虚函数的存在是为了多态。
Java 中其实没有虚函数的概念,它的普通函数就相当于 C++ 的虚函数,动态绑定是Java的默认行为。如果 Java 中不希望某个函数具有虚函数特性,可以加上 final 关键字变成非虚函数。
1、重写
2、接口
3、抽象类和抽象方法
尽管该类是抽象类,但是它仍然可以有多个成员变量,成员方法,构造函数
可以通过继承来实现抽象类的方法,核对抽象类的成员变量进行赋值
声明抽象方法会造成以下两个结果:
1、如果一个类包含抽象方法,那么该类必须是抽象类。
2、任何子类必须重写父类的抽象方法,或者声明自身为抽象类。
最终必须有子类实现该抽象方法
private私有方法,子类是无法继承得到的
final定义的方法不能被重写
static静态方法不用实例化可直接调用
1、抽象类不能被实例化
2、抽象类不一定包含抽象方法,但是有抽象方法的类必定是抽象类
3、抽象类中抽象方法只是声明,不包含方法体,就是不包含具体实现也就是方法的具体功能
4、构造方法,类方法(static修饰的方法)不能声明为抽象方法
5、抽象类的子类必须给出抽象类中的抽象方法的实现,除非该子类也是抽象类;子类重写父类的抽象方法的时候要去掉abstract关键字
例:
abstract class A_Per{
void hello(){
System.out.println("helloworld");
}
abstract void hello_demo();
}
class A_Stu extends A_Per{
@Override
void hello_demo() {
System.out.println("helloworld");
}
}
狭义的封装,就是对类的当中定义的成员变量私有化设置
广义的封装,对一些可重复利用的代码都需要进行封装,对调用细节进行隐藏,对外暴露接口名称
封装是指一种将抽象性函式的实现细节部分包装、隐藏起来的方法。
封装可以以为是保护屏障,防止该类的代码和数据被外部类定义的代码随机访问
要访问该类的代码和数据,都必须通过严格的接口控制
主要功能时在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序
1、良好的封装能够减少耦合
2、类内部的结构可以自由修改
3、可以对成员变量进行更精准的控制
4、隐藏信息,实现细节
Spring —->反射+注解
本质上它也是一种类,他称之为接口类,是一种特殊的类;作为一种功能集合,
时抽象方法的集合,通常使用interface来声明。一个类通过继承接口的方式,从而来实现接口的抽象方法。
除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。
接口无法别实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法
1、一个接口可以有多个方法(方法可以是抽象方法,也可以是静态方法);2、接口文件保存在.java结尾的文件中,文件名使用接口名;3、接口的字节码文件保存在.class结尾的文件中;4、接口相应的字节码文件必须在与包名称相匹配的目录结构中
1、接口不能用于实例化对象;2、接口没有构造方法;3、所有方法必须是抽象方法(JDK8之后可以使用default关键字修饰非抽象方法);4接口不能包含成员变量,除了static和final变量;5、接口不是被类继承了,而是被类实现;6、接口支持多继承
接口中每一个方法也是隐式抽象的,被隐式指定为public abstract
接口中可以含有变量,变量会被隐式指定为public static final
①扩展原有类的功能
②设定了规则
③降低了耦合性
抽象类可以有方法体,接口中的不行;抽象类中的成员变量可以是各种类型,而接口中的变量只能是public static final类型;一个类可以继承一个抽象类,但是可以继承多个接口
enum Color
{
RED, GREEN, BLUE;
// 构造函数
private Color()
{
System.out.println("Constructor called for : " + this.toString());
}
public void colorInfo()
{
System.out.println("Universal Color");
}
}
public class Test
{
// 输出
public static void main(String[] args)
{
Color c1 = Color.RED;
System.out.println(c1);
c1.colorInfo();
}
}
//------输出------
Constructor called for : RED
Constructor called for : GREEN
Constructor called for : BLUE
RED
Universal Color
枚举:枚举接口定义了一种从数据结构中取回连续元素的方式
位集合:实现了一组可以单独设置和清除的位或标志
向量:Vector类最主要的好处就是在创建对象的时候不必给对象指定大小,它的大小会根据需要动态的变化。
栈:实现了后进先出的数据接口
字典:定义了键映射到值的数据结构
哈希表:在用户定义键结构的基础上来组织数据的手段
属性:属性列表中每个键及其对应值都是一个字符串
集合框架被设计必须要满足以下几个目标:
1、该框架必须是高性能的,基本集合(动态数组,链表,树,哈希表)的实现也必须是高效的。2、该框架允许不同类型的集合,以类似的方式工作,具有高度的互操作性。3、对一个集合的拓展和适应必须是简单的
1、Set接口实例存储时无序的,不重复的数据。List接口实例存储的时有序的,可以重复的元素。
2、Set检索效率低下,删除和插入效率比较高,插入和删除,不会引起元素位置的改变(实现类有HashSet和TreeSet)
3、List和数组类似,可以动态增长,根据实际存储的数据长度自动增加List的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置的改变(实现类有ArrayList,LinkedList,Vector)
一般遍历数组都会采用for循环或者增强for,这两种方法都可以用在集合框架,但是还有一种方法时采用迭代器,他是一个对象,实现了Iterator接口或ListIterator接口
允许双向遍历列表和修改元素
Map<String ,String > map=new HashMap<String,String>();
map.put("1","value1");
map.put("2","value2");
map.put("3","value3");
//第一种:普通遍历,二次取值;
System.out.println("通过Map.keySet遍历key和value");
for(String key:map.keySet()){
System.out.println("key="+key+"and value="+map.get(key));
}
//第二种
System.out.println("通过Map.entrySet使用iterator迭代器遍历key和value");
Iterator<Map.Entry<String,String>> it =map.entrySet().iterator();
while(it.hasNext()){
Map.Entry<String,String> entry=it.next();
System.out.println("key="+entry.getKey()+"and value="+entry.getValue());
}
//第三种:推荐,尤其是容量大的时候
System.out.println("通过Map.entrySet遍历key和value");
for(Map.Entry<String,String> entry:map.entrySet()){
System.out.println("key="+entry.getKey()+" and value="+entry.getValue());
}
//第四种
System.out.println("通过Map.values()遍历所有的value,但是不能遍历key");
for(String v:map.values()){
System.out.println("value="+v);
}
ArrayList类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,可以添加和删除
ArrayList<E> objectName=new ArrayList<>();
//例:
ArrayList<String> sites=new ArrayList<String>();
sites.add("添加");
sites.add("添加2");
sites.add("添加3");
System.out.println("获取"+sites.get(0));
sites.remove(2);//删除,删除之后,index后的元素都往前挪一位;
System.out.println("size()方法,获取列表的长度"+sites.size());
for(int i=0;i<sites.size();i++){//遍历列表
System.out.println(sites.get(i));
}
for(String item:sites){//通过for-each遍历数组
System.out.println(item);
}
E:泛型,用于设置objectName的数据类型,只能为引用数据类型
添加 add(); 访问元素 get();修改元素set();删除元素remove();总长度size();
遍历元素for (int i =0;i<objectName.size();i++){objectName.get(i)}或者使用for(E item:objectName){item}
我们要使用引用数据类型,这就需要基本类的包装类
排序:sort,使用Collection.sort(arrayName);复制 clone() 复制一份arrayList;截取 subList()截取
方法 | 描述 |
---|---|
contains();containsAll() | 判断元素是否在arrayList;是否包含指定集合中的所有元素 |
ensureCapacity() | 设置指定容量大小的arrayList |
retainAll() | 保留arrayList中指定集合中也存在的那些元素 |
trimToSize() | 将arrayList的容量调整为元素的个数 |
removeRange() | 删除指定索引之间存在的元素 |
链表是一种常见的基础数据结构,是一种线性表,每一个节点里都存到下一个节点的地址
链表有单向链表和双向链表
ArrayList和LinkedList的适用范围:
ArrayList:频繁访问列表中某一个元素。只需要在列表的末尾进行添加和删除操作
LinkedList:需要通过循环迭代来访问列表中的某些元素。需要频繁的在列表的开头,中间,末尾,等位置进行添加和删除操作
LinkedList<String> sites=new LinkedList<String>();
sites.add("userlyz");
sites.add("github");
sites.add("io");
System.out.println(sites);//[userlyz, github, io]
sites.addFirst("lyz");
System.out.println(sites);//[lyz, userlyz, github, io];还有addLast(E)添加到链表的末尾
sites.removeFirst();
System.out.println(sites);//[userlyz, github, io];还有removeLast()删除链表的末尾元素
System.out.println("getFirst获取头部元素"+sites.getFirst());//getLast获取尾部元素
//遍历方法和遍历ArrayList差不多
方法 | 描述 |
---|---|
poll();remove() | 删除并返回第一个元素 |
contains(Object o) | 判断是否含有某一元素 |
peek();peekFirst()返回头部元素;peekLast()返回尾部元素 | 返回第一个元素 |
element() | 返回第一个元素 |
descendingIterator() | 返回倒序迭代器 |
HashSet是基于HashMap来实现的,是一个不允许有重复元素的集合;HashSet允许有null值,HashSet是无序的,即不会记录插入的顺序;HashSet不是线程安全的,如果多线程尝试同时修改HashSet则最终结果是不确定的。必须要在多线程访问时显式同步对HashSet的并发访问;
HashSet<String> sites=new HashSet<>();
sites.add("userlyz");
sites.add("github");
sites.add("io");
sites.add("io");
System.out.println(sites);//[github, io, userlyz]
System.out.println("contains:判断元素序列中是否有给定的值"+sites.contains("github"));
sites.remove("io");
System.out.println("remove() 删除元素"+sites);
//size()计算元素个数
//for-each来迭代HashSet中的元素
Map是集合容器,由键和值两部分,键和值必须是引用类型,键唯一不能重复也没有顺序
HashMap是Map的一个实现类可以允许键和值是null
Map的增删查:map.put(“1”,”Monday”);获取key对应的value:map.get(“1”);删除map.remove(“1”);
//遍历map
Map<String ,String> map=new HashMap<>();
map.put("邓超", "孙俪"); map.put("李晨", "范冰冰"); map.put("刘德华", "柳岩");
Set<String> keySet=map.keySet();
for(String key :keySet){
System.out.println(map.get(key));
}
//删除元素 remove();删除所有键值对 clear();计算元素个数 size();
//containsKey()containsValue() 检查hashMap中是否存在指定的key/value对应的映射关系
//
Iterator(迭代器)不是一个集合,他是一种用于访问集合的方法,可以用于迭代ArrayList和HashSet等集合。
// 创建集合
ArrayList<String> sites = new ArrayList<String>();
sites.add("Google");
sites.add("Runoob");
sites.add("Taobao");
sites.add("Zhihu");
// 获取迭代器
Iterator<String> it = sites.iterator();
// 输出集合中的第一个元素
System.out.println(it.next());
//循环集合元素
while(it.hasNext()) {
System.out.println(it.next());
}
Object类是所有类的父类,就是java中所有的类都继承Object,子类可以使用Object的所有方法。
拷贝 clone() ; 比较 equals();获取对象运行时的类getClass();获取对象的hash值hashCode();唤醒在该对象上等待的某个线程notify();toString();
泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。
泛型本身是参数化类型,也就是说所操作的数据类型被指定为一个参数。
java中的泛型标记符:
E:Element(在集合中使用,因为集合中存放的是元素)
T:Type(java类)
K:Key(键)
V:Value(值)
N:Number(数据类型)
?:表示不确定的java类型;类型通配符
private static <E> void printArray(E[] inputarray){
for(E element:inputarray){
System.out.println(element);
}
}
public static void main(String[] args) {
// 创建不同类型数组: Integer, Double 和 Character
Integer[] intArray = { 1, 2, 3, 4, 5 };
Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };
System.out.println( "整型数组元素为:" );
printArray( intArray ); // 传递一个整型数组
System.out.println( "\n双精度型数组元素为:" );
printArray( doubleArray ); // 传递一个双精度型数组
System.out.println( "\n字符型数组元素为:" );
printArray( charArray ); // 传递一个字符型数组
}
public static void main(String[] args) {
List<String> name=new ArrayList<String>();
List<Integer> age=new ArrayList<Integer>();
List<Number> number=new ArrayList<Number>();
name.add("userlyz");
age.add(21);
number.add(919);
getData(name);
getUperNumber(age);
getUperNumber(number);
}
public static void getUperNumber(List<? extends Number> data){//限定泛型的范围
System.out.println(data.get(0));
}
public static void getData(List<?> data){
System.out.println(data.get(0));
}
一个对象可以被表示为一个字节序列,该细节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。
serialVersionUID是用来验证版本一致性的,所以在做兼容性升级的时候,不要改变类中serialVersionUID的值;如果不设置,系统会默认给一个serialVersionUID,这样就可能会造成一种情况:
类已经序列化存储之后,又改变了类中的内容这个时候序列化,就会出现报错java.io.invalidClassException并且还会指出两个serialVersionUID不同
idea设置一键生成serialVersionUID
public static void main(String[] args) {
SerializeDemo();
DeserializeDemo();
}
//序列化对象
public static void SerializeDemo(){
Emloyee e=new Emloyee();
e.name="userlyz";
e.address="河南郑州";
e.SSN=111222333;
e.number=101;
System.out.println(e.SSN);
try{
FileOutputStream fileout=new FileOutputStream("employee.ser");
ObjectOutputStream out=new ObjectOutputStream(fileout);
out.writeObject(e);
out.close();
fileout.close();
System.out.println("已经保存完毕");
} catch (IOException ex) {
ex.printStackTrace();
}
}
//反序列化对象
public static void DeserializeDemo(){
Emloyee e=null;
try{
FileInputStream fileIn=new FileInputStream("employee.ser");
ObjectInputStream in=new ObjectInputStream(fileIn);
e= (Emloyee) in.readObject();
in.close();
fileIn.close();
} catch (IOException ex){
ex.printStackTrace();
return ;
} catch (ClassNotFoundException ex) {
System.out.println("没有找到员工类或者IO异常");
ex.printStackTrace();
return;
}
System.out.println("反序列化对象");
System.out.println("姓名"+e.name);
System.out.println("地址"+e.address);
System.out.println("SSN"+e.SSN);
System.out.println("number:"+e.number);
}
class Emloyee implements Serializable{
public String name;
public String address;
public transient int SSN;
public int number;
public void mailCheck(){
System.out.println("发送邮件到"+name+"||"+address);
}
}
java提供了两种常见的网络协议支持:
TCP:一种面向连接的的、可靠的、基于字节流的传输层通信协议,TCP保障了两个应用程序之间的可靠通信。常用于互联网协议
UDP一种无连接的协议,由于UDP缺乏可靠性且属于无连接协议,所以应用程序通常必须容许一些丢失、错误、或重复的数据包
Socket编程 ①套接字使用TCP提供了两台计算机之间的通信机制。客户端程序创建一个套接字,并尝试链接服务器的套接字;②当连接建立时服务器,会创建一个Socket对象。客户端和服务端现在可以通过对Socket对象的写入和读写进行通信
服务器端实例化一个ServerSocket对象,表示通过该服务器上的端口通信
服务器调用ServerSocket类的accept()方法,该方法一直等待,直到客户端连接到服务器给定的端口
服务器正在等待时;一个客户端实例化一个Socket对象,指定服务器名称和端口号来请求连接
Socket类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则客户端创建一个Socket对象与服务器进行通信。
在服务器端,accept()方法返回服务器上的一个新的socket引用,该socket连接到客户端的socket
TCP是一个双向通信协议,因此数据可以通过两个数据流在同一时间发送。
ServerSocket(int port) 创建绑定到指定端口的服务器套接字
ServerSocket(int port ,int backlog)利用指定的backlog创建服务器套接字并将其绑定到指定的本地端口号
ServerSocket(int port,int backlog , InetAddress address)使用指定的端口,侦听backlog和要绑定的本地IP地址创建服务器
ServerSocket()创建非绑定服务器套接字
try
{
URL url = new URL("http://www.runoob.com/index.html?language=cn#j2se");
System.out.println("URL 为:" + url.toString());
System.out.println("协议为:" + url.getProtocol());
System.out.println("验证信息:" + url.getAuthority());
System.out.println("文件名及请求参数:" + url.getFile());
System.out.println("主机名:" + url.getHost());
System.out.println("路径:" + url.getPath());
System.out.println("端口:" + url.getPort());
System.out.println("默认端口:" + url.getDefaultPort());
System.out.println("请求参数:" + url.getQuery());
System.out.println("定位位置:" + url.getRef());
}catch(IOException e)
{
e.printStackTrace();
}
url连接https/http协议的url。openConnection返回HttpURLConnection对象
如果你连接的URL为一个JAR文件。openConnection返回JarURLConnection对象
try
{
URL url = new URL("https://www.runoob.com/");
URLConnection urlConnection = url.openConnection();//
HttpURLConnection connection = null;
if(urlConnection instanceof HttpURLConnection)
{
connection = (HttpURLConnection) urlConnection;
}
else
{
System.out.println("请输入 URL 地址");
return;
}
BufferedReader in = new BufferedReader(
new InputStreamReader(connection.getInputStream()));//返回URL的输入流,用于读取资源
String urlString = "";
String current;
while((current = in.readLine()) != null)
{
urlString += current;
}
System.out.println(urlString);
}catch(IOException e)
{
e.printStackTrace();
}
安装JavaMail API 和Java Activation Framework(JAF)
System.out.println("开始发送了啊");
// 创建Properties 类用于记录邮箱的一些属性
Properties props = new Properties();
// 表示SMTP发送邮件,必须进行身份验证
props.put("mail.smtp.auth", "true");
//此处填写SMTP服务器
props.put("mail.smtp.host", "smtp.qq.com");
//端口号,QQ邮箱端口587
props.put("mail.smtp.port", "587");
// 此处填写,写信人的账号
props.put("mail.user", "*********@qq.com");
// 此处填写16位STMP口令
props.put("mail.password", "*********");
// 构建授权信息,用于进行SMTP进行身份验证
Authenticator authenticator = new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
// 用户名、密码
String userName = props.getProperty("mail.user");
String password = props.getProperty("mail.password");
return new PasswordAuthentication(userName, password);
}
};
// 使用环境属性和授权信息,创建邮件会话
Session mailSession = Session.getInstance(props, authenticator);
// 创建邮件消息
MimeMessage message = new MimeMessage(mailSession);
// 设置发件人
InternetAddress form = new InternetAddress(props.getProperty("mail.user"));
message.setFrom(form);
// 设置收件人的邮箱
InternetAddress to = new InternetAddress("*********@qq.com");
message.setRecipient(MimeMessage.RecipientType.TO, to);
// 设置邮件标题
message.setSubject("这是一个标题");
// 设置邮件的内容体
message.setContent("这是接下来的内容", "text/html;charset=UTF-8");
// 最后当然就是发送邮件啦
Transport.send(message);
System.out.println("发送完成了");
关于守护进程问题;笔记5
主要就是实现接口中的run()方法;调用Thread(Runable threadOb,String threadName)构造方法:threadOb是一个实现Runable接口类的实例,threadName是指定新线程的名字
class RunableDemo implements Runnable{
private Thread t;
private String threadName;
public RunableDemo(String threadName){
this.threadName=threadName;
System.out.println("创建线程"+this.threadName);
}
@Override
public void run() {
System.out.println("线程运行了:"+this.threadName);
try {
for (int i=4;i>0;i--){
System.out.println("Thread"+this.threadName+","+i);
Thread.sleep(50);
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("线程"+this.threadName+"退出了");
}
public void start(){
System.out.println("Starting"+this.threadName);
if(t==null){
t=new Thread(this,this.threadName);
t.start();
}
}
}
继承类必须重写run()方法,该方法时新线程的入口,他也是必须调用start()方法才能执行;这个虽然是一种多线程实现的方式,但是本质上也是实现Runable接口的一个实例
class DisplayMessage implements Runnable{
private String message;
public DisplayMessage(String message){
this.message= message;
}
@Override
public void run(){
while(true){
System.out.println(message);
}
}
}
FutureTask对象的get()方法来获得子线程执行结束后的返回值
class Demo_Callable implements Callable<Integer>{
@Override
public Integer call() throws Exception {
int i=0;
for (;i<100;i++){
//Thread.sleep(100);
System.out.println(Thread.currentThread().getName()+"|+|"+i);
}
return i;
}
}
//主函数----------------------------------
Demo_Callable demo_callable=new Demo_Callable();
FutureTask<Integer> ft=new FutureTask<>(demo_callable);
for (int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+" 的循环变量是"+i);
if(i==20){
new Thread(ft,"有返回值的线程").start();
}
}
try{
System.out.println("子线程的返回值:"+ft.get());
} catch (ExecutionException e) {
e.printStackTrace();
}
使用继承Thread类的方式创建多线程,编写简单,需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程
public static void main(String[] args) {
Student s=new Student("1",2,"3");
p(s);
}
public static void p(Object obj){
Class c1=obj.getClass();
try{
Method method=c1.getDeclaredMethod("ppp");//外部类中的private方法名是 ppp
method.setAccessible(true);
method.invoke(obj);
}catch (Exception e){
e.printStackTrace();
}
}
out: for(;;){
int index=0;
while (true){
index++;
if(index==1){
break out;
}
}
}
跳出到out标记的循环;
静态的信息,当程序已启动是最先加载;
main(String[] args){
this调用的是对象当中的信息;对象的信息在堆当中存储,还没有开辟,这时候堆为空;
}
这个问题的发现是:java多线程中发现的,有两个线程(都是死循环程序),当时都设置的守护进程,主程序结束之后就结束运行了;然后我就突发奇想,把其中一个改成用户进程,然后就发现主函数都结束好一会了,两个线程都还在运行;不管怎么设置setDaemon
问题解决
一个守护线程什么时候结束不取决于主线程什么时候结束。守护线程的作用是在后台运行任务,只要还有一个以上非守护线程没有结束(即便此时主线程已结束),程序就不会结束。而程序没结束,守护线程当然还可以继续运行;反过来,当所有非守护线程都结束了后,即便还有未结束的守护线程,系统也会马上结束这些守护线程,然后结束程序。
serialVersionUID是用来验证版本一致性的,所以在做兼容性升级的时候,不要改变类中serialVersionUID的值;如果不设置,系统会默认给一个serialVersionUID,这样就可能会造成一种情况:
类已经序列化存储之后,又改变了类中的内容这个时候序列化,就会出现报错java.io.invalidClassException并且还会指出两个serialVersionUID不同
idea设置一键生成serialVersionUID
String str= String.format("整数:%d 小数%.1f 字符串%s",1,12D,"333" );
System.out.println(str);