1:基本概念

标识符:
标识符可以包含英文字母 26 个(区分大小写) 、0-9 数字 、$(美元符号) 和_(下划线) 。 标识符不能以数字开头。 标识符不能是关键字。

1.1:关键字

类与接口的声明:class(类),extends(继承),implements(实现),interface
流程控制:if.else,switch,do,while,case,break,continue,return,default,for
异常处理:try,catch,finally,throw,throws,

final

类:不能被继承,方法:不能被重写,变量:不能被改变。final 成员变量表示常量,只能被赋值一次,赋值后值不再改变
final 修饰对象:表示对象引用的地址不能改变,但是该地址的内容是可以改变的
final Eog eog=new Eog(“欧欧”);
eog.name=”美美”;//正确的
eog=new Eog(“亚亚”);//错误的

static

“static”:全局,静态,关键字表明一个成员变量或者是成员方法可以在没有所属的类的实例变量的情况下被访问。
Java 中static 方法不能被覆盖,因为方法覆盖是基于运行时动态绑定的,而 static 方法是编译时静态绑定的。static 方法跟类的任何实例都不相关,所以概念上不适用。
加载过程:
加载父类静态代码块
加载父类静态变量
加载子类静态代码块
加载子类静态变量
加载父类普通代码块
加载父类构造函数
加载子类普通代码块
加载子类构造函数

  • Native

本地方法,本地方法与平台相关,因此使用了 Native 的程序可移植性不高。另外 native 方法在 JVM 中运行时数据区也和其它方法不一样,它有专门的本地方法栈。native 方法主要用于加载文件和动态链接库,由于 Java 语言无法访问操作系统底层信息。使用 Native 关键字说明这个方法时原生函数,与其他语言协作时使用这个方法可以被其他语言进行实现。

synchronized

synchronized:保证在同一时刻,只有一个线程可以执行某个方法或某个代码块
同时 synchronized 可以保证一个线程的变化可见(可见性),即可以代替 volatile。
可以修饰代码块,方法,静态方法,类

volatile

  • Volatile 是 Java 虚拟机提供的轻量级的同步机制(三大特性)
    • 保证可见性
    • 不保证原子性
    • 禁止指令重排

保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。(实现可见性)
禁止进行指令重排序。(实现有序性)
volatile 只能保证对单次读/写的原子性。i++ 这种操作不能保证原子性。
synchronized 和 volatile 的区别是什么?

  • volatile 是变量修饰符;synchronized 是修饰类、方法、代码段。
  • volatile 仅能实现变量的修改可见性,不能保证原子性;而 synchronized 则可以保证变量的修改可见性和原子性。
  • volatile 不会造成线程的阻塞;synchronized 可能会造成线程的阻塞。

String、StringBuffer、StringBuilder
5.1
String s=new String(“abc”) 创建了几个对象?
“abc” 创建一个对象 new String() 创建一个对象。
5.2
String 被 final 修饰,声明不可改变的对象每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,修改用 StringBuffer.append(“fkf”);方法
StringBuffer 是线程安全的,
StringBuilder 是不安全的,但是其性能却高于 StringBuffer,单线程使用 StringBuilder,多线程用 StringBuffer
5.3
String 类为什么是 final 类型
为了实现字符串池(只有当字符是不可变的,字符串池才有可能实现)
为了线程安全(字符串自己便是线程安全的)
为了实现 String 可以创建 HashCode 不可变性(Map 的 key 一般 String 用的最多原因就是这个)
5.4
indexOf():返回指定字符的索引。
charAt():返回指定索引处的字符。
replace():字符串替换。
trim():去除字符串两端空白。
split():分割字符串,返回一个分割后的字符串数组。
getBytes():返回字符串的 byte 类型数组。
length():返回字符串长度。
toLowerCase():将字符串转成小写字母。
toUpperCase():将字符串转成大写字符。
substring():截取字符串。
equals():字符串比较。
stringBuffer. reverse()字符串反转

Serilizable 和 transient

一个对象只要实现了 Serilizable 接口,这个对象就可以被序列化,实际开发中有些敏感信息(密码,银行卡)字段的生命周期仅存在于调用者的内存而不会写到磁盘里序列化,不需要在网络传输,加上 transient 即可
Instanceof:用来指出对象是否是特定类或接口或该类子类的一个实例

this 与 super

  • super :代表父类的存储空间标识(可以理解为父亲的引用)。 this :代表当前对象的引用(谁调用就代表谁)。

    1.2:变量

    局部变量与成员变量
    定义的位置不同:局部变量定义在方法内部,成员变量定义在方法外部,直接写在类中
    作用范围不一样:局部变量只有方法中才能用,成员变量都可以用
    默认值不一样:局部变量没有默认值,如果想要使用,必须手动进行赋值,成员变量会有默认值,规则与数组相同
    内存的位置不一样:局部变量位于栈内存,成员变量位于堆内存
    生命周期不一样:局部变量随着方法进栈而诞生,方法出栈而消失。成员变量随对象创建而诞生
    注:当局部变量与成员变量冲突时,根据就近原则,优先使用局部变量

    1.3:访问控制

    类中的数据成员和成员函数据具有的访问权限包括:public、private、protect、default(包访问权限)
    一、基础语法 - 图1

public 所有类可见
protected 本包和所有子类都可见(本包中的子类非子类均可访问,不同包中的子类可以访问,不是子类不能访问)
default 本包可见(即默认的形式)(本包中的子类非子类均可访问,不同包中的类及子类均不能访问)
priavte 本类可见
在非本包子类,通过父类的对象实例只能访问父类的 public 成员,不能访问 protected 成员。

2:数据类型

1)八种基本数据类型
一、基础语法 - 图2

数据范围与字节数不一定相关,float 数据范围比 long 更加广泛,但是 float 是 4 字节,long 是 8 字节。
注:double 型比 float 型存储范围更大,精度更高,所以通常的浮点型的数据在不声明的情况下都是 double 型的。
存储金额有关使用BigDecimal
2)引用类型
引用数据类型传递的是内存的使用权,是一块内存空间,它可以由多个单位同时使用。
String:字符串型,用于存储一串字符
3)数据类型转换:
自动转换:将取值范围小的类型自动提升为取值范围大的类型 。
byte、short、char‐‐>int‐‐>long‐‐>float‐‐>double
强制转换
浮点转成整数,直接取消小数点,可能造成数据损失精度。 int 强制转成 short 砍掉 2 个字节,可能造成数据丢失。
Long 转成 Integer:
LongNum.inValue();
4)包装类
基本类型与引用类型,使用基本类型在于效率,然而很多情况,会创建对象使用,因为对象可以做更多的功能,如果想要我们的基本类型像对象一样操作,就可以使用基本类型对应的包装类

基本类型 对应的包装类(位于 java.lang 包中)
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean
  • 装箱:从基本类型转换为对应的包装类对象。
  • 拆箱:从包装类对象转换为对应的基本类型。

除了 Character 类之外,其他所有包装类都具有 parseXxx 静态方法可以将字符串参数转换为对应的基本类型:

  • public static byte parseByte(String s):将字符串参数转换为对应的 byte 基本类型。
  • public static short parseShort(String s):将字符串参数转换为对应的 short 基本类型。
  • public static int parseInt(String s):将字符串参数转换为对应的 int 基本类型。
  • public static long parseLong(String s):将字符串参数转换为对应的 long 基本类型。
  • public static float parseFloat(String s):将字符串参数转换为对应的 float 基本类型。
  • public static double parseDouble(String s):将字符串参数转换为对应的 double 基本类型。
  • public static boolean parseBoolean(String s):将字符串参数转换为对应的 boolean 基本类型。

值缓存
这个就是 java8 中的 Integer 类中的一个内部缓存类(其他版本的 jdk 实现有可能不一样但是效果都是一样的),这个类的作用就是将 -128~127 之间的整型做了一个缓存,(享元模式)
这个东西注释里已经写的比较清楚了,缓存在第一次使用时初始化,可以使用 -XX:AutoBoxCacheMax=(SIZE) VM 启动参数 来改变改变之后的缓存区间为 [-128~SIZE]
其实不止是 Integer ,在 Java 中所有的整型都是有缓存的,在 Byte 中也是有的,这个缓存的大小正好也是 Byte 的范围。
Integer a=100,b=100,c=200,d=200;
System.out.println(a==b);
System.out.println(c==d);
所以,上诉答案应该是, true , false

==与 equals

==比较的是地址
equals 比较的是字符串,如果不重写比较的也是地址。
基本数据类型使用==比较的是他们的值
引用数据类型,== 比较的是他们的堆内存地址
equals 引用类型比较的是地址

值传递和引用传递

值传递(pass by value)是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
引用传递(pass by reference)是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
八种基本数据类型,在栈里面分配内存,属于值传递栈管运行,堆管存储
int 等基本数据类型,相当于传递的一个副本,属于值传递,对于其他对象一般都是引用传递,特殊的 String,会将变量放入到一个常量池中
举例:
第一个例子:基本类型
void foo(int value) {
value = 100;
}
foo(num); // num 没有被改变
第二个例子:没有提供改变自身方法的引用类型
void foo(String text) {
text = “windows”;
}
foo(str); // str 也没有被改变
第三个例子:提供了改变自身方法的引用类型
StringBuilder sb = new StringBuilder(“iphone”);
void foo(StringBuilder builder) {
builder.append(“4”);
}
foo(sb); // sb 被改变了,变成了”iphone4”
一、基础语法 - 图3

builder.append(“4”)之后
一、基础语法 - 图4

第四个例子:提供了改变自身方法的引用类型,但是不使用,而是使用赋值运算符。
StringBuilder sb = new StringBuilder(“iphone”);
void foo(StringBuilder builder) {
builder = new StringBuilder(“ipad”);
}
foo(sb); // sb 没有被改变,还是 “iphone”
一、基础语法 - 图5

builder = new StringBuilder(“ipad”); 之后
一、基础语法 - 图6

存放位置

在方法中声明的变量,如果是基本类型,其变量名和值都存放在方法栈中;如果是引用变量,所声明的变量是放在方法的栈中,该变量所指向的对象是放在堆类中的。
在类中声明的变量,如果是基本类型则存放在堆里,如果是引用,引用和对应的对象也都在堆里

3:流程控制

if……else
switch……case……break
for
do……while

3:重载与重写

重载:指在同一个类中,允许存在一个以上的同名方法,只要它们的参数列表不同即可,与修饰符和返回值类型无关。
重载只是指参数不同,返回类型不同参数相同会报错,重复定义

4:面向对象

封装,继承,多态

4.1:封装

封装就是将一些细节信息隐藏起来,对于外界不可见
方法就是一种封装,关键字 Private 也是一种封装

4.2:继承

为了复用,如果子类父类中出现重名的成员变量
Java 中的向上转型与向下转型
1 : 向上转型:大体可以理解为子类转换成父类,例子优先还是:
1 public class Animal {
2 public void eat(){
3 System.out.println(“animal eatting…”);
4 }
5 }
7 public class Cat extends Animal{
9 public void eat(){
11 System.out.println(“我吃鱼”);
12 }
13 }
15 public class Dog extends Animal{
17 public void eat(){
19 System.out.println(“我吃骨头”);
20 }
22 public void run(){
23 System.out.println(“我会跑”);
24 }
25 }
27 public class Main {
29 public static void main(String[] args) {
31 Animal animal = new Cat(); //向上转型
32 animal.eat();
34 animal = new Dog();
35 animal.eat();
36 }
38 }
39
40 //结果:
41 //我吃鱼
42 //我吃骨头
(1):虽然将子类转换成父类,但调用方法是调用的是子类的方法,这里的转型只是父类的引用指向了子类的实例。
(2):如果子类还有父类中没有的方法 w 可以调用吗 ?答案当然是不能,子类转换成父类,子类多余的方法会丢失,就像例子中 dog 的 run()方法会丢失
(3)为什么要用向上转型:父类是接口啊!接口的好处就不用说了,比如当你对所有动物全部放生,就不用一个个放生,可以 Save(Animal);就 OK
2:向下转型:简单来说就是将父类转换为子类,但是转换可就不像向上转那末好转了!理解起来也比向上转型不好理解
(1):首先注意:向下转型的前提是父类对象指向的是子类对象,就是你必须先向上转然后才能向下转,可能会有人说转上去再转下来,没有意义啊!作用就是当再次转下来的时候,就可以调用向上转丢失的方法,而且编程以后接口一多会有很多泛型编程,这样就可以针对父类进行编程,如果需要再取用子类的方法。
(2):强制类型转换:将一个子类的引用赋值给超类,编译器是允许的,但将一个超类引用赋给一个子类变量必须进行强制类型转换
public class Sys{
public static void main(String[] args) {
Animal a=new Dog(); //向上转型
a.eat();

  1. Dog aa=(Dog)a; //向下转型,编译和运行皆不会出错(正确的)<br /> aa.eat();//向下转型时调用的是子类的<br /> aa.run();
  2. Animal a2=new Animal();<br /> Dog aa2=(Dog) a2; //-不安全的---向下转型,编译无错但会运行会出错<br /> aa2.eat();<br /> aa2.run();<br /> }<br />}<br />//结果为:<br />//我吃骨头<br />//我吃骨头<br />//我会跑<br />//报错······<br />结果表明:只有先经过向上转型的才能进行向下转型,向下转型必须要进行强制类型转换,<br />(3):另外要注意两点,<br />第一:如果 Cat 向上转成 Animal,那末向下转 Animal 只能转成 Cat,不能转成 Dog,因为 Cat 怎么也不会变成 Dog<br />第二:为了安全的类型转换,向下转型时最好先 if ( Dog instanceof Animal) 判断一下,否则一旦无法转换,程序就会直接终止<br />Java 为什么只能单继承?<br />多继承的菱形继承问题<br />![](https://cdn.nlark.com/yuque/0/2021/png/21566525/1620468243704-24095602-f2a7-4f3a-9ccc-d3f52f2e1b84.png#align=left&display=inline&height=642&id=FIK4N&margin=%5Bobject%20Object%5D&originHeight=642&originWidth=1118&status=done&style=none&width=1118)<br />image-20210117214212583

4.3:多态

是指同一行为,具有多个不同表现形式。
实现原理:动态绑定,方法表
虚拟机栈中会存放当前方法调用的栈帧,在栈帧中,存储着局部变量表、操作栈、动态连接 、返回地址和其他附加信息。多态的实现过程,就是方法调用动态分派的过程,通过栈帧的信息去找到被调用方法的具体实现,然后使用这个具体实现的直接引用完成方法调用。

4.4:内部类

//定义
class Car { //外部类
class Engine { //内部类
}
}
//使用
外部类名.内部类名 对象名 = new 外部类型().new 内部类型();
非静态内部类依赖于外部类的实例,也就是说需要先创建外部类实例,才能用这个实例去创建非静态内部类。而静态内部类不需要。静态内部类不能访问外部类的非静态的变量和方法。

4.4:匿名内部类

FlyAble f = new FlyAble(){
public void fly() {
System.out.println(“我飞了~~~”);
}
};

5:抽象与接口

接口的内部主要就是封装了方法,包含抽象方法(JDK 7 及以前),默认方法和静态方法(JDK 8),私有方法(JDK 9)。
接口中所有的方法隐含的都是抽象的。而抽象类则可以同时包含抽象和非抽象的方法。
类可以不实现抽象类和接口声明的所有方法,当然,在这种情况下,类也必须得声明成是抽象的。
抽象类可以在不提供接口方法实现的情况下实现接口。
Java 接口中声明的变量默认都是 final 的。抽象类可以包含非 final 的变量。
Java 接口中的成员函数默认是 public 的。抽象类的成员函数可以是 private,protected 或者是 public。
抽象方法:使用 abstract 关键字修饰,可以省略,没有方法体。该方法供子类实现使用。
默认方法:使用 default 修饰,不可省略,供子类调用或者子类重写。 静态方法:使用 static 修饰,供接口直接调用。
私有方法:使用 private 修饰,供接口中的默认方法或者静态方法调用。
优先级:
继承>实现
当一个类,既继承一个父类,又实现若干个接口时,父类中的成员方法与接口中的默认方法重名,子类就近选择执 行父类的成员方法。
实现接口的关键字为 implements,继承抽象类的关键字为 extends
一个类可以实现多个接口,只能继承一个抽象类
设计:
抽象类:同一类事务的抽取,比如对 Dao 层操作的封装
接口:通常更像是一种标准的制定,定制系统之间的对接的标准

5:方法

5.1:构造方法

5.2:可变参数方法

JDK1.5之后,如果我们定义一个方法需要接受多个参数,并且多个参数类型一致,我们可以对其简化成如下格式:
修饰符 返回值类型 方法名(参数类型… 形参名){ }
其实这个书写完全等价与
修饰符 返回值类型 方法名(参数类型[] 形参名){ }
只是后面这种定义,在调用时必须传递数组,而前者可以直接传递数据即可。
int sum2 = getSum(6, 7, 2, 12, 2121);
//可变参数写法
public static int getSum(int… arr) {
int sum = 0;
for (int a : arr) {
sum += a;
}
return sum;
}

5.3:抽象方法及重写

转载 https://www.yuque.com/jykss/jykss/zezf4y#1rvA7