前言
一些Java中让人疑惑的重要知识点,帮助我们更好的理解代码。
正文
- Java程序的入口——main方法
public static void main(String[] args) {
// TODO Auto-generated method stub
}
main方法为java程序的入口,public static 表示这是一个公开的静态方法,方法中代码存储在静态存储区。main()方法中的public、static没有先后顺序,也可以把main()方法定义为final。只有与.java文件同名且用public修饰的类中的main()方法才能作为整个程序的入口方法。
-
java程序初始化的顺序
依次满足:
- 静态先于非静态
- 父类先于子类
- 变量先于代码块,代码块先于构造方法
-
修饰符的作用域
java修饰符作用域.png
-
java创建对象的方式
四种:
- new 出一个对象;
- 通过反射机制创建对象;
- clone()方法创建;
- 反序列化方法创建。
- 构造函数
- 构造函数必须与类的名字相同,不能有返回值(void也是返回值)
- 每个类都可以有多个构造函数,可提供不同参数(个数、类型、顺序)的构造函数
- 构造函数总是伴随着new操作一起调用(只能由系统调用,且只调用一次。)
- 构造函数不能被继承,所以它不能被覆盖,但是可以被重载,即定义多个构造函数。
- 子类可以通过super关键字来显式调用父类的构造函数。当父类没有提供无参构造函数时,子类的构造函数中必须显式地调用父类构造函数。当有父类时,在实例化对象时会先执行父类的构造函数,再执行子类的构造函数。
- 默认构造器的修饰符只跟当前类的修饰符有关(一致)。
-
浅复制与深复制
浅复制:仅复制所考虑的对象
深复制:把复制的对象所引用的对象都复制了一遍。 -
多态
多态表示当同一个操作作用在不同对象时,会有不同的语义,从而会产生不同的结果。
java提供了两种用于多态的机制,分别为通过方法的重载实现的编译时多态;通过方法的覆盖实现的运行时多态。 -
重载和覆盖
重载是在一个类中多态性的一种表现,是指在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型。
- 重载是通过不同的方法参数来区分的(个数、类型、顺序)
- 不能通过方法的访问权限、返回值类型和抛出的异常类型进行重载
- 对于继承来说,如果基类的方法访问权限为private,那么就不能在派生类对其重载。
覆盖是指派生类函数覆盖基类函数,覆盖一个方法并对其重写,以达到不同的作用。
- 派生类中的覆盖方法必须要和基类中被覆盖的方法有相同的函数名和参数
- 派生类中的覆盖方法的返回值必须和基类中被覆盖的方法的返回值相同
- 派生类中的覆盖方法所抛出的异常必须和基类(或是其子类)中被覆盖的方法所抛出的异常一致。
- 基类中被覆盖的方法不能定义为private,否则其子类只是定义了一个方法,并没有对其覆盖。
- 重载和覆盖的区别
- 覆盖是子类和父类之间的关系,是垂直关系;重载是同一个类中方法之间的关系,是水平关系。
- 覆盖只能由一个方法或只能由一对方法产生关系;重载是多个方法之间的关系。
- 覆盖要求参数列表相同;重载要求参数列表不同方。
- 覆盖关系中,调用方法体是根据对象的类型(对象对应存储空间类型)来决定;而重载关系是根据用时的实参表与形参表来选择方法体的。
-
抽象类与接口
如果一个类中包含抽象方法,那么这个类就是抽象类。
接口就是指一个方法的集合,接口中的所有方法都没有方法体。
interface MyInterface{
public int myMethod(int a ,int b);
}
接口与抽象类的相同点
- 都不能被实例化;
- 接口的实现类或抽象类的子类都只有实现了接口或抽象类中的方法后才能被实例化。
接口与抽象类的不同点
-
接口只有定义,其方法不能在接口中实现,只有实现接口的类才能实现接口中定义的方法,而抽象类可以有定义与实现,即其方法可以在抽象类中被实现。
-
接口需要实现,但抽象类只能被继承,使用接口可以间接达到多重继承的目的。
-
接口强调特定功能的实现,其设计理念是“has - a”关系;而抽象类强调所属关系其设计理念为“is - a”关系。
-
接口中定义的成员变量默认为public static final ,只能够由静态的不能被修改的数据成员,而且必须给其赋初值,其所有成员方法都是public 、abstract的,而且只能被这两个关键字修饰。而抽象类可以有自己的数据成员变量,也可以有非抽象的成员方法,而抽象类中的成员变量默认为default,这些成员变量在子类中可以重新定义也可以重新赋值,抽象类中的抽象方法不能用private、static、synchronized、native等修饰符修饰,同时方法必须以分号结尾,并且不带花括号。所以,当功能需要累积时,用抽象类;不需要累积时,用接口。
-
接口被运用于实现比较常用的功能,便于日后维护或者添加删除方法;而抽象类更倾向于充当公共类的角色,不适用于日后重新对里面的代码进行修改。
简单地说,接口是一种特殊形式的抽象类,使用接口完全有可能实现于抽象类相同的操作,但一般而言,抽象类多用于在同类事物中具有无法描述的方法场景,所以当子类和父类存在有逻辑上的层次结构时,推荐使用抽象类;而接口多用于不同类之间,定义不同类之间的通信规则,所以当希望支持差别较大的两个或者更多对象之间的特定交互行为时,应该使用接口。
此外,接口可以继承接口,抽象类可以实现接口,抽象类也可以继承具体类。抽象类也可以有静态的main方法。 -
内部类
静态内部类是指被声明为static的内部类,它可以不依赖于外部类的实例而被实例化,而通常的内部类需要在外部类实例化后才能实例化。静态内部类不能与外部类有相同的名字,不能访问外部类的普通成员变量,只能访问外部类中的静态成员和静态方法(包括私有类型)。
非静态内部类中不能定义静态成员,静态内部类不能访问外部类的非静态成员。 -
break、continue、return
- break用于直接强行跳出当前循环,不再执行剩余代码
- continue用于停止当次循环,回到循环起始处,进入下一次循环操作。
- return语句是一个跳转语句,用来表示从一个方法返回(返回一个值或者其他复杂类型),可以使程序控制返回到调用该方法的地方。
- 带标识的break语句,用于跳出多重循环。
- final、finally、finalize
- final用于声明属性、方法和类,分别表示属性不可变、方法不可覆盖和类不可被继承。
- finally作为异常处理的一部分,表示这段语句最终一定被执行,经常被用在需要释放资源的情况下。
- finalize是Object类的一个方法,在垃圾回收器执行时会调用被回收对象的finalize()方法,可以覆盖此方法来实现对其他资源的回收,如关闭文件等。
-
assert
assert即断言,是一种软件调试的方法,提供了一种在代码中进行正确性检查的机制。 -
volatile关键字
volatile是一个类型修饰符,用来修饰被不同线程访问和修改的变量。被volatile类型定义的变量,系统每次用到它时都是直接从对应的内存当中提取,而不会利用缓存。所有线程在任何时候所看到的volatile修饰的变量都是相同的。 -
strictfp
strictfp是strict float point 的缩写,指精确浮点,它用来确保浮点数运算的准确性。 -
基本数据类型
java一共提供了8种原始的数据类型(boolean,byte,short,int,long,float,double,char),这些数据类型不是对象,而是java语言中不同于类的特殊类型,这些基本类型的数据变量在声明后就会立刻在栈上被分配内存空间。注意:String 不是基本数据类型。除了这8种数据类型外,其他类型都是引用类型。
java基本数据类型.png
-
java运算符优先级
运算符优先级.png
-
Java IO
在java语言中,输入和输出都被称为抽象的流,流可以被看作一组有序的字节集合,即数据在两设备之间传输。
流的本质是数据传输,根据处理数据类型的不同,流可以分为两大类:字节流和字符流。字节流和字符流最主要的区别为:字节流在处理输入输出时不会用到缓存,而字符流用到了缓存。
字节流继承于InputStream与OutputStream,字符流继承于Reader与Writer。 -
Java Socket
网络上的两个程序通过一个双向的通信连接实现数据的交换,这个双向链路的一端称为一个Socket。Socket也称为套接字,可以用来实现不同虚拟机或不同计算机之间的通信。
Socket分为两种类型:面向连接的Socket通信协议(TCP,传输控制协议)、面向无连接的Socket通信协议(UDP,用户数据报协议)。 -
Java加载class文件的原理机制
class加载方式分为隐式加载与显式加载两种。隐式加载指的是程序在使用new等方式创建对象时,会隐式的调用类的加载器把对应的类加载到JVM中。显式加载指的是通过直接调用class.forName()方法来把所需的类加载到JVM中。 -
Java中容易引起内存泄露的地方
- 静态集合类。
- 各种连接,如数据库、网络、IO等等。
- 监听器
- 变量不合理的作用域。
- 单例模式可能会造成内存泄露。(静态的单例对象持有引用)
- Java中的堆和栈
- 栈内存主要是用来存放基本数据类型与引用变量。
- 堆内存用来存放运行时创建的对象。一般来讲,通过new 关键字创建出来的对象都存放在堆内存中。
- 集合框架
- Set 表示数学意义上的集合概念。最主要的特点就是集合中的元素不能重复,该接口有两个实现类:HashSet、TreeSet。其中TreeSet实现了SortSet接口,因此TreeSet容器中的元素是有序的。
- List又称为有序的Collection。它按对象进入的顺序保存对象,所以它能对列表中的每个元素的插入和删除位置进行精确地控制。同时,它可以保存重复的对象。该接口的实现类有:LinkedKist,ArrayList和Vector。
- Map提供了一个从键映射到值的数据结构。键唯一,值可以重复。实现该接口的类有:HashMap,TreeMap,LinkedHashMap,WeakHashMap,IdentityHashMap。
-
迭代器
迭代器(Iterator)是一个对象,它的工作是遍历并选择序列中的对象,它提供了一种访问一个容器对象中的各个元素,而又不必暴露该对象内部细节的方法。
import Java.util.*;
public class IteratorTest{
public static void main(String[] args){
List<String> ll = new LinkedList<String>();
ll.add("first");
ll.add("second");
ll.add("third");
ll.add("fourth");
ll.add("fifth");
for(Iterator<String> iter = ll.iterator;iter.hasNext();){
String str = (String)itr.next;
System.out.println(str);
}
}
}
-
Collection和Collections
Collection是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。实现该接口的类主要又List和Set,该接口的设计目标是为各种具体的集合提供最大化的统一操作方式。
Collections是针对集合类的一个包装类,它提供一系列静态方法以实现对各种集合的搜索、排序、线程安全化等操作,其中大多数方法都是用来处理线性表。Collection.sort(list)。 -
线程,进程,多线程
线程是指程序在执行过程中,能够执行程序代码的一个执行单元。
进程是指一段正在执行的程序,一个进程可以拥有多个线程,各个线程之间共享程序的内存空间(代码段、数据段和堆空间)及一些进程级的资源(例如打开的文件),但是各个线程拥有自己的栈空间。
进程与线程的对比关系.png
多线程的便利:
- 减少程序的响应时间;
- 线程的创建与切换开销更小;
- 提高CPU的利用率;
- 简化程序的结构,便于理解与维护。
Java多线程的实现方法:
- 继承Thread类,重写run()方法。
- 实现Runnable接口,并实现该接口的run()方法。
- 实现Callable接口,重写call()方法。
只有调用线程的start()方法才能真正达到多线程的目的,run()方法只是当作普通函数来调用。
多线程同步的实现方法:
- 使用synchronized关键字。
- wait()方法与notify()方法。
在synchronized代码被执行期间,线程可以调用对象的wait方法,释放对象锁,进入等待状态,并且可以调用notify()方法或notifyAll()方法通知正在等待的其他线程。notify()方法仅唤醒一个线程(等待队列中的第一个线程),notifyAll()方法唤醒所有等待这个对象的线程,让他们去竞争,获得锁。 - Lock,以阻塞的方式获取锁。
参考资料
《java核心技术》
《java编程思想》
《java程序员面试笔试宝典》
网友评论