Java基础总结

Java基础


面向对象的特性
  • 封装,将程序实现的细节隐藏起来,公开的方法显示对象的功能。
  • 继承,子类继承父类后,具有父类的功能和属性,避免代码重复。
  • 多态,父类可以声明子类,运行时依然保持子类的特征。
Java与C++的区别

1 Java是解释型语言,一次编译到处运行,Java首先需要将代码编译为字节码文件,之后由虚拟机解释执行,C++为编译型语言,则编译时将代码编译为机器指令,机器可以直接运行效率高但是不能跨平台。

2 Java不具有指针的概念,由虚拟机负责管理内存,消除了野指针带来的影响,C++可以使用指针操作内存,程序运行有风险。

3 Java不需要程序员释放内存,释放内存的操作由虚拟机的垃圾回收来完成,C++需要在使用完对象后析构函数释放内存。

4 Java不支持多继承,但提供了接口,可以实现多个接口,C++支持多继承的语法。

初始化顺序

Java的类加载过程决定了初始化的顺序,静态对象或者代码加载过一次之后就不再进行加载,如果类未曾被虚拟机加载过,则按照以下顺序加载:

1 父类的静态对象和静态代码

2 子类的静态对象和静态代码

3 父类的非静态对象和代码

4 父类的构造器

5 子类的非静态对象和代码

6 子类的构造器

权限访问控制

Java中采用了4个关键字进行类、方法、变量的权限控制,分别为:

  • public 可以被所有类访问
  • protected 同一个包下的类或者不同包下的子类
  • default 在同一个包下的类访问
  • private 只能在同一个类中访问
深复制、浅复制
  • 浅复制只会复制对象的基本数据类型,对象如果存在引用的话只复制地址,当拷贝的对象改变引用中的基本数据类型时,被拷贝的对象的基本数据类型也会变化。
  • 深复制需要将基本数据类型和引用类型中的所有数据均复制,两个对象进行任何操作时不会相互影响。
反射机制

通过class.forname()可以获取其他对象的类信息、方法信息以及变量信息,通过反射可以创建类的对象,调用对象方法等操作。

多态

多态分为编译时多态和运行时多态,分别通过重载和重写实现的,重载在同一个类中实现,同一个方法可以具有不用的参数类型或者个数,而重写指的是子类对父类重写,子类可以获取父类的方法和属性,父类声明的子类对象在编译时为父类类型,但在运行时为调用子类的方法。

抽象和接口
  • 抽象可以有自己的普通方法,而且可以声明权限,接口只能包括抽象方法,子类在继承抽象类或者实现接口时都需要实现抽象方法。
  • 抽象中的变量权限范围更加广泛,接口中只能为public final static类型的变量,在之后的版本中加入了default控制。
  • 一个类只能继承一个抽象类,但可以实现多个接口。
  • 在设计理念上,接口反应的是like a的关系,而抽象指的是is a的关系。
内部类

内部类主要包括四种,分别为静态内部类,非静态内部类,局部内部类,匿名类。

this super

this用来指代当前类的对象实例,super可以调用父类的方法。分别可以用于重载和重写中。

final

final可以用来修饰成员变量,表示该变量不可修改,修饰成员方法则代表该方法不可以被重写,修饰类则表明该类不能被继承。

instanceof

instanceof是一个运算符,不是关键字,用于判断前者实例是否为后者类的子类对象。

基本数据类型

基本数据类型包括char、byte、short、int、double、float、long、boolean八种类型

基本类型所占字节范围
byte1-2^7~2*7-1
char20~2^16-1
short2-2^15~2*15-1
int4-2^31~2*31-1
float432位单精度
double864位双精度
long8-2^63~2*63-1
自动装箱

自动装箱是Java引入的语法糖,方便了引用与基本类型的转换操作,可以将基本数据直接赋值给该数据类型的包装类,即完成了自动装箱操作,反之,也可以将包装类型的数据赋值给基本类型的变量,即完成了拆箱操作。由于装箱过程的底层实现原因,Integer范围在[-128-127]的数值,不会创建新的对象,此范围的的数值比较时返回为true,而此范围之外的数值比较返回值为false。

类型转换

类型转换主要分为两种,自动类型转换和强制类型转换

范围低的数据类型向范围高的数据类型转换时,发生自动类型转换,未补满的位置为0

范围高的数据类型向范围低的数据类型转换时,发生强制类型转换,多余的位强制丢弃

编码方式

Java的编码方式为Unicode,每个字符占有2个字节,范围为0-2*16-1,String是由char组成的,但是中英文所占的字节不相同,中文占用两个字节,英文占用一个字节。

euqals和hashcode

equals和hashcode都是Object类的默认方法,它们都是用来比较两个类是否相同,两个对象equals方法返回值为true时,hashcode返回值也一定为true,但是如果hashcode方法返回为true时,equals方法返回值不一定为true。hashcode()方法主要用于解决Java中的集合问题,向一个集合中添加元素时,判断其中是否已经有一个同样的值如果用equals方法遍历耗费时间,所以采用hash结构存储数据,可以减少查询时间。

当重写equals方法时,同时也需要重写hashcode方法。

String StringBuffer StringBuilder

String是不可变类,当对象被创建后,字符串的值不能再改变。

StringBuffer是可变类,用于多线程下操作大量数据。

StringBuilder也是可变类,用于单线程下操作大量数据。

Error和Exception

异常主要分为检查型异常和非检查型异常,检查型异常在编译器阶段就会检测出来,而非检查型异常需要等到程序运行时才能检测,主要分为Error和Exception,Error是系统错误包括内存溢出,栈溢出等,程序无法控制,而Exception是程序可以控制的,出现异常时可能为数组越界异常、空指针异常、参数类型错误异常、运算错误异常等。

字节流和字符流

文件传输时可以采用两种方式传输,以字节的方式传递,主要继承InputStream和OutputStream,以字符的方式传递,主要继承Reader和Writer。

NIO BIO AIO

BIO是同步阻塞的IO,一个线程需要请求数据时,如果数据未能及时返回,则一直处于等待状态。
NIO是同步非阻塞的,一个线程需要请求数据时,如果数据未能及时返回,则会将现在的状态返回该线程,线程则不断发出请求直到返回数据。
BIO是异步非阻塞的,当一个线程请求数据时,可以先完成其他的任务,当数据返回时,发送给线程数据返回完成的状态。

NIO操作面向缓冲区,数据从Channel读取到Buffer缓冲区,随后在Buffer中处理数据。NIO主要包括三个组件:

  • buffer,当写入数据到buffer中时,buffer会记录已经写入的数据大小。当需要读数据时,通过flip()方法把buffer从写模式调整为读模式;在读模式下,可以读取所有已经写入的数据。当读取完数据后,需要清空buffer,以满足后续写入操作。
  • channel,提供map()方法可以将文件映射到内存也就是buffer中,通道可以进行读和写,也可以进行异步操作,通道不与程序直接交互,而是通过buffer进行传递。
  • selector,用于检查一个或多个NIO Channel的状态是否处于可读、可写。
序列化

为了使创建的Java对象保存在文件或者进行网络传输,需要对其进行序列化处理,需要该类实现Serializable和Externalizable两个接口之一。反序列化则是将保存的二进制文件转化为对象的操作。

ArrayList和LinkedList

ArrayList是基于数组实现的,默认数组大小为10,当数组已满时,扩展数组大小为原来的1.5倍,按下标访问或设置数组元素时效率很高,当按下标插入或者删除元素时,则由于对齐原因,需要移动部分元素的位置。LinkedList则是基于链表实现的,方便插入和删除元素,但是读取元素使需要遍历整个链表,用时较长,但是由于本身采用链表实现,没有容量限制。

HashMap和TreeMap

HashMap采用hash的方法解决冲突问题,它是基于数组和链表实现的,当插入一个元素时,首先计算该元素的hash值,如何在数组中没有冲突,则将此元素插入到该位置,如果在数组中有冲突,则需要在该冲突点的链表中查找是否有相同的元素,如果没有,则在链表中插入新值,如果有相同元素,则新值不能插入,当插入新值时,map的容量已经达到临界条件时,即容量*负载因子,需要进行扩容操作,将容量扩展为原来的2倍,重新计算每个元素的hash值,完成元素的重新划分。

TreeMap在插入新的元素时,会对其进行排序操作,当遍历TreeMap时,得到的序列是有序的。

LinkedHashMap与HashMap不同的是,它是按照数据的插入顺序存储的,当遍历LinkedHashMap存储的元素时,得到的结果与插入时的顺序一致。

创建对象

创建对象主要发生在以下的几种情况下:

1 最常用的新建一个对象
2 实现clone方法实现对象克隆
3 序列化一个对象,之后反序列
4 反射方法创建对象

内存划分

JVM负责内存的划分,主要包括程序计数器、虚拟机栈、虚拟机堆、方法区等部分。

程序计数器,记录当前正在执行指令的行号,是线程私有的。

虚拟机栈,是方法的运行空间,局部变量都存储在栈中,当方法运行结束后,虚拟机栈重新置为空,是线程私有的。

虚拟机堆,Java创建的对象都存在堆中,引用存在栈中,引用指向堆中的地址,是线程共享的。

方法区,用于存储类加载的信息,是线程共享的。

常量池,是方法区的一部分,用于存储符号引用以及字符串信息,是线程公有的。

垃圾回收

垃圾回收是Java特有的内存回收机制,Java创建对象后会占用大量的内存,在对象不再使用后需要将该内存区域释放,判断对象是否还需使用主要采用了引用计数法和可达性分析。

引用计数法指的是每个对象在创建后会有一个引用指向堆中的位置,当引用被改变或者达到生命周期时,引用变量-1,当有一个新的引用指向该实例后,该实例的引用变量+1,当引用变量为0时,就可以释放该区域了,引用计数法存在的问题是如果有两个对象中的变量互相指向对方,则无法释放两个对象的内存。

可达性分析算法是指建立一个根节点,其他对象实例的节点都指向根节点,当某个实例与根节点不再相连时,即可以释放该实例内存区域。

常用垃圾回收算法主要包括三种,标记清理算法、复制算法和标记整理算法。

  • 标记清理算法指的是当内存占用空间已满时,清理需要释放的内存区域,不能释放的区域位置不变。
  • 复制算法指的是将内存区域分为两个部分,当其中部分已满时,将不能释放的区域复制在另外半边,之前半边的内存区域全部清空。
  • 标记整理算法指的是当内存占有空间已满时,清理需要释放的内存区域,将不能释放的区域移至内存区域的一边对齐。

另外根据对象的生存时间不同,将其分为新生代和老生代,新生代又被分为Eden和Surviver区,新生代按照复制算法清理垃圾,老生代按照标记清理或标记整理算法回收内存。当新建一个对象实例后,首先在Eden区分配空间,当Eden空间已满并且该对象实例不需要清理,则将此实例转入Surviver区,如果在该区经过多次GC后依然存在,则将其转入老年代。

类加载

类的加载是由类加载器完成的,类加载器分为根加载器、扩展类加载器、自定义类加载器,当一个类需要加载时,按照以上顺序依次加载,类加载器完成的工作包括加载、连接和初始化,其中连接包括验证、准备和解析。

  • 加载,装载二进制文件
  • 验证,验证class文件是否符合要求
  • 准备,为类变量分配空间,在方法区完成
  • 解析,将符号引用转化为直接引用
  • 初始化,调用类加载器完成类的初始化

类的初始化发生情况如下所示:

  • 新建一个对象
  • 获取或重置类静态变量
  • 调用类的静态方法
  • 反射方式创建对象
  • 子类初始化前对父类初始化
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值