自学内容网 自学内容网

java基础万字笔记

前言

此篇文章为本人在初学java时所记录的java基础的笔记,其中全面记录了java的基础知识点以及自己的一些理解和要注意的点。由于该笔记是边学边记录而成,所以基本很多模块内都会有一些我本人后期记录的知识穿插进去,导致一些模块内的内容并不连贯,但是整篇笔记绝对是干活满满,没有什么废话,所记录的都是有价值的知识点。

文章目录

    • 前言
    • java的特性
    • 基本数据类型
    • 变量
    • 运算符
    • 字符串
    • 输入与输出
    • 循环
    • 大数值
    • 数组
    • 泛型
    • 对象和类
    • 继承
    • 代理

java的特性

1.简单性

2.面向对象

3.分布式:很多不同的计算机同时计算同一个任务

4.健壮性:代码改起来不容易出错

5.安全性:有一定的检测能力

6.体系结构中立:是指的不同结构的CPU7.

7.可移植性:指的操作系统

8.解释型:重新翻译为c和汇编

9.高性能

10.多线程

11.动态性

基本数据类型

整数:byte(8bit) short(16bit) int(32bit) long64bit)

浮点数:float(32bit) double(64bit)

字符:char 根据编码决定,可以是8/16/32bit

布尔:boolean(32bit)

整数

0/1 1bit

8bit = 1B(1字节)

数据类型取值范围

int: -231~231-1

short: -215~215-1

byte: -27~27-1

long: -263~263-1

原码 反码(原码除符号位,各位按位取反) 补码(反码+1)

正数的补码是它本身

浮点型

float浮点数表示方式:(有效范围只有6-7位)

0 10001000 0000000000000100001000

​ 256(0-255)

​ 136 x 528 y

表示数字(2^(x-127)) * y

例:0.5=2^(126-127)*1

这种组合方式距离0越近越密集,距离0越远越稀疏

double表示方式:(有效位数为15位)

0 00000000000 0000000000000000000000000000000000000000000000

​ x 11位 y

(2^(x-1023))*y

因为有效位数有限,因此浮点数并不靠谱

char类型

char x1 = ’ ’ 任意符号都可以放在里面

编码:用编号来表示一堆数据(都是8的倍数)

其他编码包含ASCII编码(8位),因为它短。例如有的Unicode字符可以用一个字节表示,有的需要两个字节,就是因为包含ASCII编码,所以可以用一个字节表示

char类型储存时要先指定一种编码去存

char类型的数据可以进行运算,是把对应编码的值进行运算,也可以转化为int类型的编码值

boolean类型

只有trur和flase两种值

申请空间大的原因是防治阻塞,提高运行速度

变量

变量初始化:变量首次赋值

c语言中变量声明后会有默认值,java中变量声明后若不赋值就是没有值

java中使用变量必须先进行声明并赋值

汉字占多少字节与编码有关,字母在所有编码中都占据一个字节

GBK 使用两个字节表示一个汉字。

UTF-8 对于大部分汉字,UTF-8 编码使用三个字节表示一个汉字,也有可能会占4字节。

UTF-16 编码使用两个或四个字节表示一个字符,对于大部分汉字,UTF-16 编码使用两个字节表示一个汉字。

用final修饰的是常量,常量一般所有字母大写

final修饰基本类型加不可变类型(内部数据不可动)

final的作用

1.fianl阻止常量第二次赋值

2.final修饰的类不可被继承

3.final修饰的方法不可被重写

4.final修饰的变量一定程度上可以阻止指令重排序,保障多线程下的可见性

运算符

基本运算符

+ - * / %

java中小数除以小数还是小数,整数除以整数还是整数

引用 import import java.lang.Math.*引用java下的Math文件夹的所有文件

Math.pow(m,n) m的n次方

数据转化时可能会造成数据丢失

(实线不会丢失,虚线会丢失数据)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ba2AI2iP-1721318045209)(https://i-blog.csdnimg.cn/direct/d20d3cf205c746ebb7b1303f213428e7.jpeg)]

容量大的类型不能转化为容量小的类型,容量小的类型可以转化为容量大的类型

++a是指先对a加一再进行计算,a++是指先进行计算再加一

a=a++,此时a不会发生变化(坑)a=++a此时a会发生变化

两位运行符

!= 不等于

== 等于

&& 和

|| 或

三连运算符

= >或者< ? 例如: int m1 = a >b ? 20 : 30;如果a>b为真命题则m1=20,如果a>b为假命题则m1=30。

位运算符

1.&与运算:将数字转化为二进制,对应位置只要有一个0则该位置运算结果为0,否则对应位置都是1.最后所有的位置组成一个新的二进制数。

2.| 或运算:将数字转化为二进制,对应位置只要有一个1则该位置运算结果为1,否则对应位置都是0.最后所有的位置组成一个新的二进制数。

3.^异或运算:相同为1,不同为0

4.~非运算 :每一位按位取反

移位运算符

>>n 右移n位 相当于除以2的n次方(右移左边补的是符号位,左边全是0补的就全是0,左边是1,最左边补的就是1)

>>n 左移n位 相当于乘以2的n次方(N进制,左移m位,相当于乘以n的m次方)

>>>往右移,左边肯定补0

计算机底层就是移位运算

优先级

&&的优先级比||高,+=是右结合运算符 a+=b+=c = a+=(b+=c)

结合性指的计算顺序

字符串

从引用类型开始,同一种类型的大小就不一样了

任何引用类型都是由基本类型组成的

String x1=" ";

public class Test{
     public static void main(String[]  xxx){
            String x1 = "asfagag";//定义字符串
            String x2 = "撒娇看";
            String x3 = "dafklanfagn";
            String x4 = x1 + x2;//字符串拼接
            System.out.println(x4);
            String x6 ="afag" + 65;
            int a = 90;
            float b = 234.56F;
            String x7 =x6 + a + b;//拼接时加上数字
     }     
}

字符串拼接时可以加上数值,仍是字符串。

不可变字符串

不能在原地址修改字符串的数据,因为所占内存大小会发生变化(基本类型变量名和数值在内存中是挨着的,引用类型不是挨着的)

引用类型原理:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8kYfED6l-1721318045212)(https://i-blog.csdnimg.cn/direct/9a6ab40542b243fc89162e7276682171.jpeg)]

字符串检测相等

基本类型检测相等是检测数值是否相等,引用类型检测相等是检测指向地址是否相同(面试点)

开辟新的地址存储: String x3 = new String(“aaa”);

equals

字符串可能内存中的值相等但地址不相等,例如利用new开辟了新的地址,此时可以用equal检测相等

x1.equals(x3)检测字符串x1和x3是否相同

equals在比较其他类型时比较的是地址,只有在比较字符串时比较的是值

字符串常量池

创建双引号的字符串时会检查常量池中有无该字符串,如果没有会在常量池中创建一个空间储存该字符串,如果创建时常量池已经有了一个一样的字符串则会直接引用常量池中的(但是用new创建的字符串不进常量池)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xKkQtC4B-1721318045214)(https://i-blog.csdnimg.cn/direct/95c7b53733614e6bafc0d47379cbdf3f.jpeg)]

JDK 6及以前:字符串常量池位于方法区(Method Area)。

JDK 7至JDK 8:字符串常量池的一部分仍然位于方法区,但也开始逐渐转移到堆(Heap)中。

JDK 9及之后:字符串常量池完全被移动到了堆中。

空串与nul

String x1=null;//NULL(真正的什么都没有) 

String x2 ="x2";//空字符串  底层实现时是{'\0'},表面上隐藏了

null和空字符串不是一个概念.

码点与代码单元

获取字符串中第n个字符的编码的方法:

1.直接用codePointAt()来获取;

2.先获取第n个字符,在通过转化来获取编码

String x1 = "asfaafafagag";
int w1 = x1.length( ); //获取字符串x1的长度
char w2 = x1.charAt(3);//获取x1中的第四个字符
int w3 = x1.codePointAt(3);//获取第四个字符的编码(较难记)
int w4 = w2;//获取第四个字符的编码(好记)

一些常用的string方法

字符串截取

substring(n,m) 范围左闭右开,从0开始算 (常用)

例:x1.substring(0,3)截取x1字符串的前3个字符

char charAt(int index)

返回给定位置的代码单元

int compareTo(String other)

按字典顺序,如果字符串位于other之前,返回一个负数;如果字符串位于other之后返回一个正数;如果两个字符串相等返回0。

int indexOf(String str)

返回与字符串str匹配的第一个子串的开始位置。这个位置从索引0开始计算,如果代码中不存在str则返回-1

int length()

返回字符串的长度,底层判断的代码单元的数量,但有的字符会占据两个单元,

因此在大部分情况下可以用length判断字符串的字符数,但在小部分情况下会判断错误

String replace(CharSequence oldString,CharSequence newString)

返回一个新字符串。这个字符串用newString代替原始字符串中所有的oldString。

例:path.replace(“n”,“m”)

替换的另一种方法:

假定一段路径记作字符串 path,其中以 “.” 作为分隔符。现需将路径加密,加密方法为将 path 中的分隔符替换为空格 " ",请返回加密后的字符串。

public String pathEncryption(String path) {
       StringBuilder str = new StringBuilder();
       for(int i = 0;i<path.length();i++){
           if(path.charAt(i) == '.'){
               str.append(" ");
           }
           else{
               str.append(path.charAt(i));
           }
       }
       return str.toString();
    }

String split()

将字符串以规定字符串为分隔切割

public class Test{
        public static void main(String[]  xxx){
                String x1 = "asfaafakcncxjsxjxjxkxjxfagag";
                String[ ] arr = {"sda","dafag","xbbns"};
                String[ ] arr2 =x1.split("j");//把x2以j为分割切割
                System.out.println(arr2.length);
            }
}

构建字符串

1.先构建一个新的空字符串构建器 例:StringBuilder b = new StringBuilder( );

2.每次添加字符串时用append方法 例:b.append(“afgaa”); b.append(“xbnnc”);

3.需要使用时用toString方法 例:String a =b.toString(); System.out.println(b.toString( ));

这种方法速度极快(比单纯的“+”快得多)

原因:

内存占的比想象的大得多,每个变量的所占空间都是4kb起步。储存数组时也是4kb,可根据数组的类型来找到数组中的每一个数据

(计算机内存中有无数个小存储单元组成,每个小单元存储一个字节(1b),4096个小单元组成一个大单元,

每个大单元得地址就是第一个小单元得地址,如此读取一个地址就可以读取到4kb的数据。)

因为字符串不可变,所有使用”+“添加字符串时,每次添加都需要再次开辟一个4kb的空间来添加组成新的字符串,多次添加后所占空间大

而使用StringBuilder开辟空间时,可以指定多大的空间,后续添加字符串时可以直接在此空间中添加,不用开辟新的空间

buffer机制:申请多大的空间的基本类型数组,需要添加数据时直接添加,不用担心短时间内因为内存不够而去申请新的空间,

可以在持续添加一定的数据后再去申请新的空间,这样可以节省内存,通常用于数据量大的时候(以后会见到很多名字中带buffer的,底层都是不同类型的数组)

buffer常用于文件流,网络流

流:基本类型数组

**System.currentTimeMillis():**获取java当前的时间戳,从1970年1月1日开始计算

例:long start = System.currentTimeMillis();

for循环中的语句可以放到括号中来,要以逗号隔开,在每次循环的最后执行

例:这两种写法for循环的结果是一样的

for(int i = 0 ;i<10; i++)
{
    System.out.println("+++++++");
    System.out.println("=======");
    System.out.println("#######");    
}
for(int i = 0 ;i<10;System.out.println("======="),System.out.println("#######"), i++)
{        
   System.out.println("++++++++");
}

输入与输出

输入

1.public static void main(String[] xxx){

String[] xxx不仅用来启动主方法还用来传参(python php 等也如此)

可以在执行时进行传参 如:java Test 输入1 输入2 输入3 输入4…

import  java.util.*;
public class Test{
         public static void main(String[]  xxx){
                for(int i=0; i<xxx.length; i++){
                          System.out.println(xxx[i]);
                 }      
         }
}

2.Scanner方法

例:

import java.util.*(依靠这个)
Scanner x = new Scanner (System.in);
int x1 = x.nextInt( );输入的整数值给x1
int x2 = x.nextInt( );输入的整数值给x2

nextInt 整数

nextDouble 浮点数

nextLine 字符串

多个连续输入时,回车和空格键都可以

输出

System.out.println()

格式化输出

System.out.printf("%d==%s==%tx==%c==%f")

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9kypItDh-1721318045215)(https://i-blog.csdnimg.cn/direct/8d0700717a244748866c5e353d3ca5ac.jpeg)]

文件输入与输出

读取文件

Scanner in = new Scanner(Paths.get(“C:\mydirectory\myfile.txt”),“UTF-8”)

地址和编码

全部语言大括号{}的原理都是栈

在cmd和linux中ctrl+c是中断指令

循环

for循环

while循环

if-else判断

switch选择

switch中的case可选类型

1.类型为char,byte,short或int的常量表达式

2.枚举常量

3.从java SE 7开始,case标签还可以是字符串字面量

在Java中,"switch击穿"是指在使用 switch 语句时,当一个 case 匹配成功后,没有加上

break 关键字而继续执行下一个 case 的情况

大数值

真正的项目中需要精确计算的要用java,math中的BigInteger和BigDecimal来代替基本类型中的整数和浮点数

BigInteger类实现了任意精度的整数运算,BigDecimal类实现了任意精度的浮点数运算

例如:BigInteger x1 = new BigInteger(“3000000000000000000057873473737”)

使用这两个类的数据不能使用±*/符号,要用add和multiply方法

BigInteger x3 = x1.add(x2)

BigInteger x4 = x.multiply(x2)

数组

定义int类型的数组

int[] arr = {1,2,3,4};
int[] arr2 = new int[]{1,2,2,4,5,6};
int[] arr3 = new int[10];
arr3[0] = 15;
arr3[1] = 52;

只有基本类型的一维数组,数据才会在物理地址上严格连续

java的引用类型完全等价于c语言中的指针

每个数组的地址也是数组中的第一个的元素的地址,并且获取数组的第n跟元素就是第一个元素的地址+(n-1)个长度

在计算机中如果没有一个地址指向该数组,那么该数组会被记为无效

范围大的数组类型可以包括范围小的数组类型 例:float[] arr = {23.56F,88.21F,23,5}

定义二维数组

int[][] arr={ {1,2,3},{4,5,6} } ;

定义三维数组

int[][][] arr={{{1,2,3},{4,5,6} },{{7,8,9},{10,11,12}} };

二维数组直接指向的区域都是地址
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rQGQ92iN-1721318045215)(https://i-blog.csdnimg.cn/direct/c635308eeba9406a8aba94ecf49d21ef.jpeg)]

引用类型的一维数组数据物理地址不连续,例如:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VeCbXY31-1721318045216)(https://i-blog.csdnimg.cn/direct/03de95d24ee9431ca77c589d11121ba0.jpeg)]

更改引用类型数组中的元素是更改其元素的地址,让其指向更改的值,而原来的值会被销毁,例如:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JyetXSuf-1721318045217)(https://i-blog.csdnimg.cn/direct/7dfeeb8a606c468faf9408f423b3d578.jpeg)]

将数组以字符串的形式输出 Arrays.toString(数组名)

System.out.println(Arrays.toString(arr));

将数组排序 Arrays.sort(数组名)

Arrays.sort可以对任何类型的数组进行排序(内部原理是快速排序,对引用类型排序需要实现comparator接口)

Arrays.binarySearch(arr2,m)在数组arr2中查找m

for each循环

for( 数组的数据类型 w :数组名) { }//让w依次代表数组arr中的每个元素

例:for(int w : arr){} for(String w : arr2){} for(Object w : arr3){}

泛型

泛型就是可以存放多种数据

一个泛型栈:

public class StackDemo <W>{
  private W[] arr = (W[]) new Object[6];
  private int putindex = 0;
  
  public void put(W x) {
      if(putindex == arr.length) {
          W[] arrnew = (W[]) new Object[arr.length * 2];
          for(int i = 0; i < putindex; i++) {
              arrnew[i] = arr[i];
          }
          arr = arrnew;
      }
      arr[putindex] = x;
      putindex++;
  }
  public W get() {
      if(putindex == 0) {
          return null;
      }
      putindex--;
      return arr[putindex];
  }
}

一个泛型队列

public class QueueDemo <W>{
  private W[] arr = (W[]) new Object[6];
  private int putindex = 0;
  private int getindex = 0;
  
  public void put(W x) {
      // 存4个,取出2个,再存4个,取出2个,再存6个,取8个,存6个,取6个,存7个,取5个
      if(putindex - getindex == arr.length) {
          W[] arrnew = (W[]) new Object[arr.length * 2];
          for(int i = getindex; i < putindex; i++) {
              arrnew[i%arrnew.length] = arr[i%arr.length];
          }
          arr = arrnew;
      }
      arr[putindex % arr.length] = x;
      putindex++;
  }
  public W get() {
      if(putindex == getindex) {
          return null;
      }
      getindex++;
      return arr[(getindex-1)%arr.length];
  }
}

对象和类

一个类相当于一个图纸

进程:有自己的主方法并依托自己的主方法运行起来的程序

程序运行需要数组空间,java中就是jdk

**什么是对象?

首先对象是堆内存当中的一块内存空间。是由类所构建出来的一条实例,类是构建对象的一个模板。

内存图

jdk中有 方法区(最大),栈,堆,计数器,本地方法栈

内存图如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DWA1nVzX-1721318045218)(https://i-blog.csdnimg.cn/direct/bfd03e062de14d62a21352f39414eb1c.jpeg)]

方法区存放类信息和静态信息常量池,

存放对象和字符串常量池,

存放方法顺序拷贝运行,

程序计数器来记录何时入栈与出栈起到辅助作用,

本地方法栈用来翻译栈,翻译为操作系统认识的方法(其他语言中也需要被翻译),翻译为操作系统内核方法,这样才能调动驱动

Java在运行时不只会使用Java内部内存区的本地内存,因为使用本地方法栈,所以也会消耗操作系统本身的内存

IO操作(和其他硬件进行交互数据)时会对内存产生巨大消耗

Java运行时用到哪个类,哪个类的类信息进入方法区

java中的class文件,用多少进入内存多少,并且只要被关联调用,也会进入内存

静态方法进入内存内相当于直接被造出来了,可以直接使用(类.方法名字),非静态不能直接调用,要有对象才能调用

java中调用方法时是把方法拷贝一份入栈,每一份都是独立的

每个对象对创建时头信息都会记录着该对象的类信息

多个方法进栈组成了线程栈

线程栈的栈顶始终表示正在执行的方法

照着类造出的个体就是对象,也叫实例

类中被静态修饰方法只有一份,不是静态修饰的方法在对应的每个对象中

对象和类

当一个类被使用时,它的父类也会被加载到内存中

Java的几个特点:封装,继承,多态,(抽象)

构造方法名字要与类名保持一致,父类的构造方法一定优先于子类调用

public class Computer{
      public Computer(){
                System.out.println("lllllll")}
     public Computer(int m){
                System.out.println("xxxxxxx")}
     public Computer(String s,int m){
                System.out.println("牛牛牛牛牛")}
}
//在主方法中调用
public class Test{
       public static void main(String[]  xxx){
           Computer x1 = new Computer(34);
           Computer x2 = new Computer("56da",69);
           Computer x3 = new Computer();
           System.out.println(x1);
           System.out.println(new Computer(34).toString());
    }
}

当输出对象的时候,输出的是对象的类型和地址

例:输出上面代码中的x1,输出结果为Computer@地址

原因:每个类中默认有toString方法,用来返回对象的类型和地址,可以在类中自己写进行更改,当输出对象时会默认输出该对象的toString方法


Date deadline 定义了一个对象变量deadline,它可以引用Date类型的对象,但是变量deadline不是一个对象变量

静态的方法可以直接通过类调用,也可以通过对象调用

如在Person类中写了一个静态的方法

public static Person of(String m,int n){
    return new Person(m,n);
}

就可以在主方法中用类直接调用of方法,实现了直接调用Person的静态方法,返回了一个Person对象w

Person w = Person.of(“ada”,12);

java中不能通过操作其他变量使一个基础类型变量的值改变,c中可以,但是java中对于引用类型来说可以

我们所说的值不止包括基础类型的值还包括引用类型的值和对象

引用传递传递的是句柄的地址,值传递传递的是基本类型或是对象值的地址

java中没有引用传递,只有值传递

对象的地址也是值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G1WTb4DA-1721318045218)(https://i-blog.csdnimg.cn/direct/cab3777ae10d4c26b0ca70b115bfeacc.jpeg)]

举例说明:下面程序的输出结果还是33,m1中改变p1p2p3不会对a和c产生影响,但是方法m2可以改变a中age的值

public class Test{
              public static void main(String[]  xxx){
                  Person a = new Person( );
                  a.age = 33;
                  Person c = new Person( );
                  c.age = 10;
                  m1(a,c);
                  System.out.println(a.age);
           }
           public static void m1(Person p1, Person p2){//这边改了方法内新建对象的指向对上方没有影响
                 Person p3 = p1;
                 p1 = p2;
                 p2 = p3;
           } 
           public static void m2(Person p1, Person p2){//这边改了对象中的值,会对上方有影响
                 int w = p1.age;
                 p1.age = p2.age;
                 p2.age = w;
           } 
}

更改器和访问器

**访问器:**可以访问到类中的私有成员的公共方法

更改器:可以更改类中的私有成员的公共方法

可以灵活得更改访问对象中得私有值

不同语言中的public和private表示的范围不一样

public class Person{
    private int age;
    public String name;
    public Person child;
    public int m1(){     //访问器(这样不安全,不能做到只读,可能会被修改)
        return age;    
    }
    public void m2(int x){//更改器
        age=x;    
    }
    public int[ ] m3( ){ //这样是安全的,可以做到只读,不会被下面的方式更改
        int[ ] qq = new int[ arr.length ];
        for(int i =0; i<arr.length;i++){ 
            //通过拷贝一份再返回,这样就不会被更改原有的值,因为只能更改拷贝的那一份
            qq[i] = arr[i];
            }
        return qq;
       }
}

访问器默认不安全

例:
public class Test{
      public static void main(String[]  xxx){
            Person a = new Person( );
            int w =a.m1( );
            int[ ] ss =a.m3( );//访问器
            ss[0] = 99;//此处值被更改了,访问器不安全
            int[ ] ww =a.m3( );//访问器,两次访问的是同一地址
            System.out.println(ww[0]);
     } 
}

深浅拷贝

深拷贝:拷贝的变量有自己储存数据的地方 (改自己对别人无影响)

例: int a=9;int b=a;

浅拷贝:没有自己指向的区域,只是指向同一个区域(改自己对别人有影响,除非是字符串一样的不可变类型)

例:person b = a; int [] mm = ss;

引用类型深拷贝,先开辟一个空间,再将数据拷贝下来,如上面将访问器变安全

封装的目的是不让外界感知,不暴露它的真实地址

final不修饰复杂类型,没什么意义,只能修饰基本类型(或者是内部不可变的类型)

被static修饰的方法放在静态常量池,每个对象只存一份。

加上static就是静态域,每个类中只有一个静态域,它属于类中

静态常量:被static和final修饰的常量

静态方法(加上static):可以通过类名直接调用

例:Math.pow(x,a)

基本类型入参是深拷贝,方法内参数改变不影响原有基本类型参数

注解

方法上面加上@表示注解信息

一个程序中依托主方法运行起来的,操作系统会把其当成一个进程,否则会当成一个线程。

重载

同一个类中不能出现名字相同的方法(名字一样但是入参不一样可以存在,这样也叫重载)

默认域初始化

new出来的对象中的数据有默认值,数值为0,布尔值为false,引用类型为null(一定要是new出来的)

初始化块

代码块的优先级高于构造方法,静态的代码块优先级更高

public class Person{
    public int age;
    public String name;
    public Person(){
        System.out.println("构造方法");    
    }
    {
        System.out.println("代码块1");
        //实例对象时会优先执行代码块   
    }
    static
    {
        System.out.println("静态代码块1"); 
        //静态的代码块优先级更高   
    }
}
//因此调用时会输出
//静态代码块1
//代码块1
//构造方法

静态代码块只有类被第一次使用时才被执行一次,由首个正在生成的对象触发(注意下方代码)

非静态的代码块才会随着类被多次使用而多次执行

public class Person{
    public int age;
    public String name;
    public Person(){
        System.out.println("构造方法");    
    }
    {
        System.out.println("代码块1");
        //实例对象时会优先执行代码块   
    }
    static
    {
        System.out.println("静态代码块1"); 
        //静态的代码块优先级更高 
       }
    public static Person w = new Person();
    //首次执行时只会执行前两个代码块1和构造方法,不会执行下面的两个静态代码块
    //因为静态代码块由首个正在生成的对象触发,该对象已经是第二个生成的方法了,它在第一个生成的方法内
    static{
        System.out.println("静态代码块2");  
        }
    static{
        System.out.println("静态代码块3");  
        }    
}     

当出现继承的情况

对象初始化执行顺序(不包含父类):父类静态—子类静态—父类非静态—子类非静态

去了公司后取得包的路径名字大多数以com或cn开头

类加载的顺序:静态初始化语句-》初始化块-》非静态初始化语句-》非静态初始化块-》构造函数

对象锁:

非静态方法在每个对象中都有一份,当对某一个对象加锁时,其他对象会被锁住,导致无法调用

类锁:针对的是静态类,当对该类的某个对象加锁时,整个类会被锁住

为什么要有异常?

因为和别的部分关联时,有些方面不可控,可能是硬件出问题,人为问题(例如传参错误)等方面

正常情况出现异常会导致线程中断,借助异常类把可能会出问题的地方标注出来,try,catch标注后,一旦出了错线程不会中断,会继续运行

继承

类,父类,子类

基于继承的类具有多态的特性

多态:多种形态,例一个 Employee 变量既可以引用一个Employee 类对象, 也可以引用一个 Employee 类的任何一个子类的对象

继承的子类可以用super来使用父类的方法

public class B extends A{
    public int height;
    public void m2(){
        System.out.println("我是类B中定义的方法m2")   
    }
    public void m1(){
        super.m1();
        System.out.println("在类B中调用类A中定义的方法m1")      
    }
}

构建子类对象时一定会先生成父类对象

子类调用父类构造方法时一定要放在第一行,否则会报错

java中一个类只能有一个父类,但可以有多个子类

父类中的private类型不会被继承

不同类的对象不能直接进行强制类型转换,有继承关系的对象才可以,

如x2=(b)x1,合法但是不一定对,该代码使x2与x1指向同一个对象,当指向的对象是B类型的对象或是B类子孙后代类的对象才一定合法

强制类型转化

引用类型对象也可以强制类型转换,但是得符合多态

要看转化的对象是不是自己子孙后代的对象

有一种特殊例外:某种类型被泛型代表时,并向object类型进行转化时可以

当new一个子类时,它的祖宗类也会被创建,辈分越高越先被创建。

子类构造器

使用父类构造方法要用super

public Manager(String name, double salary, int year, int month, int day)
{     super(name, salary, year, month, day);
      bonus = 0;
}

**instanceof:**判断这个对象的类是不是其这个类的对象或子孙后代类的对象

object类

object类是所有类的父类

object类的方法

equals(Object obj):比较两个对象是否是引用的同一个内存地址的变量(是不是指向同一个对象),如果是返回true,不是返回false

equals的作用:

object类中的作用,String类中的作用(见上面字符串检测相等),或其他写中重写的作用(String类重写了equals方法,所以可以用来比较字符串)

如果重新定义equals方法,其必须重新定义hashCode方法,以便用户可以将对象插人

到散列表中,因为在使用hashmap时需要这两个配合使用

getClass():

获取该对象的所属类型

hashCode():

每个对象都有自己的hashCode

散列码(hashcode) 是由对象导出的一个整型值。

哈希码是散列码,散列码局部来看没有规律,整体看下来均匀

不同对象的hashCode有极小概率重复,但是散列码不一样的一定是不同的对象(重点面试题)

notify():

将等待状态的线程唤醒

notifyAll():

将所有等待状态的线程唤醒

**toString()****:**默认输出所属类型和内存地址

**wait():**让线程进入等待状态

抽象类

抽象:提取共性,约定共性,比如所有动物都要会移动,但是移动的方法不一样

抽象类的作用就是提取共性,凡是继承这该类都必须具备的这些功能

抽象类在使用时无法直接实例化自己,只能在多态中使用,也就是子类在实例化时会带动抽象地父类实例化

包装器与装箱

基本类型都有对应的包装类

IntegerLongFloatDoubleShortByteCharacterVoidBoolean

包装类全部都是因为泛型而产生,例:ArrayList aa = new ArrayList()

基本类型变引用类型叫做装箱,引用类型变基本类型叫拆箱

包装类的128陷阱

包装类两个值大小在-128到127之间时可以判断两个数相等,两个会公用同一个对象,返回true,

但是超过个数就会不等,会变成两个对象,返回false

枚举

也是一种类,只是限定了对象的个数.声明时对象就已经固定好了。例:

public enum AAA{
    AA(10,"小明")BB(20,"小五")CC(30,"小张")DD(40,"小阿")private int age;
    private String name;
    private AAA(int x,String y){
        age = x;
        name = y;    
    }
    public int getage(){
        retrun age;    
    }
}
public static void main(String[] agrs){
    AAA x1 = new AAA.BB;
    System.out.println(x1.getname())
}

反射

能够分析类信息的能力叫做反射

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b97QxXaL-1721318045219)(https://i-blog.csdnimg.cn/direct/dcb54a32226f4546a8202ad0019d9cf4.jpeg)]

有几种获取类信息的方式

1.getName这个方法将返回类的名字。对于某个类的实例getClass获取该对象

例:System.out.println(e.getClass().getName() + " " + e.getNameO);

2.调用静态方法 forName 获得全类名对应的 Class 对象。

例:

String dassName = “java.util.Random”;

Class cl = Cl ass.forName(dassName);

3.如果 T 是任意的 Java 类型(或 void 关键字)T.class 将代表匹配的类对象。

例:

Class cll = Random。

class; class cl2 = int.class;

Class cl3 = Double[].class;

newlnstance( )获取通过反射方式得到的类的对象

newinstance可以通过一个类的无参构造器来创建一个对象

反射可以获取到类的一切信息

类名字(类修饰,类注解) 属性(修饰,类型,名字,注解)方法(修饰符,。。。。。

获取类信息

假如当我们获取到类class1后

class1.getDeclaredFields():获取全部的全局变量,并放入数组当中

class1.getfields():获取public修饰的全局变量,并放入数组当中

class1.getDeclaredFields(“变量名”):能够获取所有修饰符修饰的全局变量,并用Field接收

class1.getfields(“变量名”):能够获取public修饰符修饰的全局变量,并且用Field接收

class1.getDeclaredMethods():获取全部的方法

class1.getMethods():获取public修饰的方法

代理

代理是通过一个对象去代理另外一个对象,进行间接访问(对另一对象的功能进行增强)

第五章的代理(invoke)针对普通方法

第六章的代理针对接口类和抽象类,实际应用时主要针对接口类

接口类和抽象类不能有自己的对象,因此获取类信息后不能创建对象

可以通过直接new使用的都不需要代理,代理的场景都是提前不知道类的名字叫什么,都是先用反射生成一个对象,调用其方法

静态方法不需要生成对象,但也要依靠反射调用

静态代理的流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v81PKnFx-1721318045220)(https://i-blog.csdnimg.cn/direct/0746625c70f346dfb5d43d1f03fa0342.jpeg)]

例子:代理类增强了核心类Pay的功能

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s2nZ6wGv-1721318045221)(https://i-blog.csdnimg.cn/direct/60fb9ce70c7a46b2be6f03555d2a1720.jpeg)]


原文地址:https://blog.csdn.net/m0_62902381/article/details/140525608

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!