Java基础

错题

1、

1
2
3
4
5
6
7
public class Test {
public static void main(String args[]) {
int x = -5;
int y = -12;
System.out.println(y % x);
}
}

取余取头,取模取尾

1.取余 rem(3,2)=1 rem(-3,-2)=-1 rem(3,-2)=1 rem(-3,2)=-1

2.取模 mod(3,2)=1 mod(-3,-2)=-1 mod(3,-2)=-1 mod(-3,2)=1

2、

重载 overload 就是同一个类中,有多个方法名相同,但参数列表不同(包括参数个数和参数类型),与返回值无关,与权限修饰符也无关

调用重载的方法时通过传递给它们不同的参数个数和参数类型来决定具体使用哪个方法,这叫多态

重写就是子类重写基类的方法,方法名,参数列表和返回值都必须相同,否则就不是重写而是重载

权限修饰符不能小于被重写方法的修饰符。重写方法不能抛出新的异常或者是比被重写方法声明更加宽泛的检查型异常

重写(overriding):指在继承情况下,子类中定义了与其父类中方法具有相同型构的新方法,就称为子类把父类的方法重写了。这是实现多态必须的步骤。

重载(overloading):指在同一个类中定义了一个以上具有相同名称,但是型构不同的方法。

返回值不能作为重载的依据

3、

Java 面向对象编程有三大特性:封装、继承、多态。

封装:隐藏对象的属性和实现细节,仅对外公开访问方法,控制在程序中属性的读和写的访问级别

继承:可以理解为,在一个现有类的基础之上,增加新的方法或重写已有方法,从而产生一个新类

  • 继承都是单继承
  • 接口是多继承多实现

多态:相同的事物,调用其相同的方法,参数也相同时,但表现的行为却不同。

  • 继承是多态得以实现的基础
  • 实现多态的三个必要条件
    1. 继承:在多态中必须存在有继承关系的子类和父类。
    2. 重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
    3. 向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。
类型 private 无修饰 protected public
同一类 可访问 可访问 可访问 可访问
同一包中的子类 不可访问 可访问 可访问 可访问
同一包中的非子类 不可访问 可访问 可访问 可访问
不同包中的子类 不可访问 不可访问 可访问 可访问
不同包中的非子类 不可访问 不可访问 不可访问 可访问

Java 中类可分为以下三种:

  • 普通类:使用 class 定义且不含有抽象方法的类。
    • 普通类可以继承(extends)普通类,可以继承(extends)抽象类,可以继承(implements)接口。
  • 抽象类:使用 abstract class 定义的类,它可以含有或不含有抽象方法。
    • 抽象类可以继承(extends)普通类,可以继承(extends)抽象类,可以继承(implements)接口。
  • 接口:使用 interface 定义的类
    • 接口只能继承(extends)接口

4、

sleep()方法(休眠)是线程类(Thread)的静态方法,调用此方法让当前线程暂停执行指定的时间,将执行机会(CPU)让给其他线程,但是对象的锁依然保持,因此休眠时间结束后会自动恢复(线程回到就绪状态,请参考第66题中的线程状态转换图)。wait()是Object类的方法,调用对象的wait()方法导致当前线程放弃对象的锁(线程暂停执行),进入对象的等待池(wait pool),只有调用对象的notify()方法(或notifyAll()方法)时才能唤醒等待池中的线程进入等锁池(lock pool),如果线程重新获得对象的锁就可以进入就绪状态。

5、

image-20210402165050662

java中long类型自动转换为float类型

6、

volatile保证了其他线程的立即可见性,就没有保证原子性

由于有些时候对 volatile的操作,不会被保存,说明不会造成阻塞。不可用与多线程环境下的计数器

上下界泛型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class Test_2 {
public static void main(String[] args) {
List<? extends B> list1 = new ArrayList<>(); // 上界
List<? super B> list2 = new ArrayList<>(); // 下界
A a = new A();
B b = new B();
C c = new C();
Object o = new Object();
// list1.add(o); 不能添加任何元素,因为List中具体是B的哪种子类无法确定
// list1.add(a);
// list1.add(b);
// list1.add(c);
o = list1.get(0);
a = list1.get(0);
b = list1.get(0);
// c = list1.get(0); 编译错误,编译器无法向下转型
// list2.add(o); 编译错误,
// list2.add(a); 因为List中具体是B的哪种父类无法确定
list2.add(b);
list2.add(c);
o = list2.get(0);
// a = list2.get(0); 编译错误,因为List中具体是B的哪种父类无法确定,无法向下转型,而Object是所有类的父类
// b = list2.get(0);
// c = list2.get(0);
}
}

class A {}

class B extends A {}

class C extends B {}

上界

上界用 extends 关键字声明,表示参数化的类型可能是所指定的类或者其任意子类。例如<? extends B>,泛型的上界就是 B 类。

形如 List<? extends B>,具体哪一种不能确定,既可以是 B,也可以是 C。在尝试执行 add() 方法时,List中的类型不能确定是具体哪一种,所以会编译报错。在执行 get() 方法时,不管是 B 还是 C,都可以以 A 类对象来接收。所以 List<? extends B> 不能添加元素,具有只读属性,只能获取。

下界

下界用 super 关键字声明,表示参数化的类型可能是所指定的类型或者其任意父类。例如<? super B>,泛型的下界就是 B 类。

形如 List<? super B>,具体哪一种不能确定,既可以是 B,也可以是 A,直至 Object类。在尝试执行 add() 方法时,虽然 List 的具体类型不能确定,但是根据多态, B 类及其子类的对象肯定都可以被赋值给 B 的对象,所以只能添加 B 类及其子类的对象。在尝试执行 get() 方法时,List 中的类型是 B 类或者其父类的具体一种,向上直至 Object 类,所以只能将获取的元素赋值给 Object 对象。

Integer

1
2
3
4
5
6
7
8
9
Integer a = 1000;
Integer b = 1000;

System.out.println(a == b); // false

Integer c = 100;
Integer d = 100;

System.out.println(c == d); // true

Debug 进入第一行:

1
2
3
4
5
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}

IntegerCache.low 是 -128

IntegerCache.high 是 127

Integer 有个内部类 IntegerCache,缓存了 -128 ~ 127 的 Integer 对象

这个范围内都是一个对象,超过这个范围就 new ,所以 1000 为 false

MySQL

一个字段同时满足多个条件

image-20210329192032372

Interface

接口是一种特殊的抽象类

接口中的变量默认是public static final 的,方法默认是public abstract 的

image-20210531114839065

接口就是提供一种统一的’协议’,而接口中的属性也属于’协议’中的成员.它们是公共的,静态的,最终的常量.相当于全局常量.
抽象类是不’完全’的类,相当于是接口和具体类的一个中间层.即满足接口的抽象,也满足具体的实现.
如果接口可以定义变量,但是接口中的方法又都是抽象的,在接口中无法通过行为来修改属性。有的人会说了,没有关系,可以通过实现接口的对象的行为来修改接口中的属性。这当然没有问题,但是考虑这样的情况。如果接口A中有一个public访问权限的静态变量a。按照Java的语义,我们可以不通过实现接口的对象来访问变量a,通过A.a = xxx;就可以改变接口中的变量a的值了。正如抽象类中是可以这样做的,那么实现接口A的所有对象也都会自动拥有这一改变后的a的值了,也就是说一个地方改变了a,所有这些对象中a的值也都跟着变了。这和抽象类有什么区别呢,怎么体现接口更高的抽象级别呢,怎么体现接口提供的统一的协议呢,那还要接口这种抽象来做什么呢?所以接口中不能出现变量,如果有变量,就和接口提供的统一的抽象这种思想是抵触的。所以接口中的属性必然是常量,只能读不能改,这样才能为实现接口的对象提供一个统一的属性。

通俗的讲,你认为是要变化的东西,就放在你自己的实现中,不能放在接口中去,接口只是对一类事物的属性和行为更高层次的抽象。对修改关闭,对扩展(不同的实现implements)开放,接口是对开闭原则的一种体现。

乱七八糟

String 内部是 byte[] 字节数组实现

Java 中的 char 是 Unicode 编码,Unicode 编码占两个字节,就是 16 位,足够存储一个汉字

abstract 类

  • abstract 类不能与 final,static 一起使用。final修饰方法,子类可以调用,但不能覆盖。
  • abstract 类可以有 private 成员,但最好不要,因为私有和抽象放在一起,子类如果想重写父类的私有方法根本继承不过来,也就无法重写
  • abstract 类中可以有非抽象方法
  • abstract 类中可以都是非抽象的,但是抽象方法一定要在类和接口中

在 main() 方法中给出的字节数组,如果将其显示到控制台上,直接标准输出流 System.out.println()

  • out 是 java.lang.System 类中的一个字段,out 是“标准“”输出流,public static final PrintStream out,
    out是PrintStream类型,PrintStream是包装流,你传入什么,他就输出什么

类变量 = 静态变量,区分成员变量

  • 类加载过程中只是对类变量进行初始化赋值(非真正的值),并没有对成员变量初始化,成员变量是实例化的时候才搞的

image-20210601144832738

image-20210601144910496

在集合中

  • vector:就比arraylist多了个同步化机制(线程安全),因为效率较低,现在已经不太建议使用。在web应用中,特别是前台页面,往往效率(页面响应速度)是优先考虑的。
  • stack:堆栈类,先进后出
  • hashtable:就比hashmap多了个线程安全
  • enumeration:枚举,相当于迭代器
  • 除了这些之外,其他的都是非线程安全的类和接口。

Java程序初始化顺序:

  1. 父类的静态代码块
  2. 子类的静态代码块
  3. 父类的普通代码块
  4. 父类的构造方法
  5. 子类的普通代码块
  6. 子类的构造方法

日志的级别之间的大小关系如右所示:ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF

Log4j建议只使用四个级别,优先级从高到低分别是 ERROR > WARN > INFO > DEBUG

log4j在运行期间是不可以重新设置的(springboot可以动态修改日志级别(https://blog.didispace.com/spring-boot-1-5-x-feature-1/))

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
float func3()
{
long i= 3;
return i;
}

longfloat,这个是对的

loat占4个字节为什么比long8个字节大呢,因为底层的实现方式不同。
浮点数的32位并不是简单直接表示大小,而是按照一定标准分配的。
1位,符号位,即S
接下来8位,指数域,即E。
剩下23位,小数域,即M,取值范围为[1 ,2 ) 或[0 , 1)
然后按照公式: V=(-1)^s * M * 2^E
也就是说浮点数在内存中的32位不是简单地转换为十进制,而是通过公式来计算而来,通过这个公式虽然,只有4个字节,但浮点数最大值要比长整型的范围要大。

方法重写 两同两小一大原则:

  1. 两同:方法名和参数列表相同
  2. 两小:返回值或声明异常比父类小(或相同)
  3. 一大:访问修饰符比父类的大(或相同)

方法重写要注意的事项:
1.方法重写时, 方法名与形参列表必须一致。
2.方法重写时,子类的权限修饰符必须要大于或者等于父类的权限修饰符。
3.方法重写时,子类的返回值类型必须要小于或者等于父类的返回值类型。
4.方法重写时, 子类抛出的异常类型要小于或者等于父类抛出的异常类型。

default:https://my.oschina.net/dongtianxi/blog/757554

javac.exe是编译.java文件

java.exe是java虚拟机

javadoc.exe用来制作java文档

jdb.exe是java的调试器

javaprof.exe是剖析工具

Java体系结构包括四个独立但相关的技术:

  • Java程序设计语言

  • Java.class文件格式

  • Java应用编程接口(API)

  • Java虚拟机

    当我们编写并运行一个Java程序时,就同时运用了这四种技术,用Java程序设计语言编写源代码,把它编译成Java.class文件格式,然后再在Java虚拟机中运行class文件。当程序运行的时候,它通过调用class文件实现了Java API的方法来满足程序的Java API调用

String对象不可变、StringBuffer对象可变的含义:

举个例子:

String str = “aa”; str = “aa”+”bb”; 此时str的值为”aabb”,但是”aabb”不是在开始的字符串”aa”后面直接连接的”bb”,而是又新生成了字符串”aabb”,字符串”aa”一旦被初始化,那么它的值不可能再改变了。

StringBuffer strb = StringBuffer(“aa”); strb.append(“bb”); 此时的strb的值也为”aabb”,但是”aabb”是直接在开始的字符串”aa”后面连接的“bb”,并没有生成新的字符串。

String str =
“”;
System.out.print(str.split(“,”).length);

输出1

str.split(",")方法是把str字符串根据分割符","划分成一个字符串数组,如果str字符串中找不到分隔符",",则把整个str字符串放入字符串数组的第一个元素。因此str.split(",").length=1。

image-20210603115252491

抽象类中可以构造方法,接口不可以

线性结构

线性结构是一个有序数据元素的集合。 其中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的。
常用的线性结构有:线性表,栈,队列,双队列,数组,串。
非线性结构中各个数据元素不再保持在一个线性序列中,每个数据元素可能与零个或者多个其他数据元素发生联系。根据关系的不同,可分为层次结构和群结构。
常见的非线性结构有:二维数组,数组,广义表,树(二叉树等),图。(其中数组是由多个一维数组组成的,所以不再是线性结构)

二叉树

参考

二叉树、平衡二叉树、满二叉树、完全二叉树、二叉搜索树、平衡二叉搜索树、红黑树、线索二叉树、哈夫曼树

image-20210628104442184

完全二叉树是到最后一个叶子结点之前每个节点都不为空

平衡二叉树父节点的左子树和右子树的高度之差不能大于1

二叉搜索树是左边小于根节点,右边大于根节点

平衡二叉搜索树既满足平衡二叉树条件有满足二叉搜索树条件(红黑树)

哈夫曼树是最优二叉树,是一种带权路径长度最短的二叉树

  • 权值越大的叶子节点越靠近根节点,权值越小的叶子节点越远离根节点。
  • 只有度为0(叶子节点)和度为2(分支节点)的节点,没有度为1的节点。
  • 没有强行说限制一定要0表示左子树,1表示右子树

图的拓扑排序

线索二叉树

二叉树在线索化后,仍不能有效求解的问题是后序线索二叉树中求后序后继

无向图边数的两倍等于各顶点度数的总和

array.sort((a,b)=>Math.abs(a-3)-Math.abs(b-3));

(a,b)=>Math.abs(a-3)-Math.abs(b-3);

箭头函数表示:当Math.abs(a-3)>Math.abs(b-3)时,a放在b后面,Math.abs(a-3)<Math.abs(b-3)时,不交换位置,也就是说数组中的每一项减去3的绝对值越大越靠后。这里主要考的是对sort()方法的掌握。