面向对象
面向对象比面向过程的性能低,但是面向对象有容易维护、容易复用、容易扩展,面向对象有封装、继承、多态特性,很容易写出低耦合的代码,使系统更加灵活,系统便于维护。
面向过程
面向过程的性能要高于面向对象,因为每次类调用时都要创建实例化,所以开销比较大,比较消耗资源,如果当性能是最重要的考虑因素的时候,比如单片机、嵌入式一般采用面向过程开发
1.简单易学
2.跨平台性
3.安全性
4.面向对象
5.可靠性
6.支持多线程
7.编译与解释并存
JVM使java运行字节码的虚拟机。JVM有针对不同系统的特点实现,目的是使用相同的字节码,他们会给出相等的结果
在Java中,JVM可以理解的代码叫做字节码(拓展名.class),它不面向任何处理器,只面向虚拟机。Java语言通过字节码的形式,在一定程度上解决了传统语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以字节码并不针对一种特定的机器,因此,Java程序不用重复编译便可在多种不同的操作系统的计算机上运行。
需要注意的是.calss到可执行的二进制机器码的过程中,JVM有两种方式:
一种是解释器,一种是JIT编译器。如果是热点程序会走JIT编译器,否则会走解释器
Java虚拟机是运行字节码的虚拟机。JVM有针对不同系统的特定实现,目的是用相同的字节码,能得出相同的结果。也就是不同系统的JVM实现了Java语言的:“一次编译多次运行”的关键所在
JDK是功能齐全的软件开发工具包,它拥有JRE所拥有的一切,还有编译器和工具。它能够创建和编译程序
JRE是Java运行时的环境,他是已编译Java程序所需的所有内容的集合,包括Java虚拟机(JVM),Java类库,java命令和其他的一些基础构建。但是,他不用于创建新程序。
同:都是面向对象的语言,支持封装继承多态
异:1. java是不提供指针操作内存,程序内存更加安全
2.Java的类是单继承的,C++可以实现多继承;虽然类不能多加载,但是接口时可以多加载的
3.Java有自动内存管理机制,不需要程序员手动释放无用内存
形式上:字符常量是单引号引起的一个字符;字符串常量是双引号的若干符号
含以上:字符常量相当于一个整型值(ASCII值),可以参加表达式运算;字符串常量代表一个地址值(该字符串在内存中存放的位置)
占内存大小:字符常量只占有两个字节(Java中);字符串常量占若干个字节
构造器不能被Override(重写),但是可以被Overload(重载),所以你可以看到一个类中有多个构造函数的情况
重载是同一个方法能够根据输入数据的不同,做出不同处理
重写是当子类继承父类的相同方法,输出数据一样,但是要做出有区别与父类的相应处理时,你就要覆盖父类的方法
重载(两同一不同)
发生在同一个类中,方法名必须相同,参数列表(个数,参数类型,顺序)不同,与方法返回值,权限修饰符无关
重写
重写时发生在与运行期,是子类对父类的允许访问的方法的实现过程的重新编写
注意
巧计口诀:两同两小一大
子类的返回值类型要小于等于父类类型
子类方法声明抛出的异常类应比父类方法声明抛出的异常小或就是父类抛出的异常
子类的权限修饰符访问权限要大于父类权限修饰符访问权限
将类的某些信息隐匿在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问
好处:1.只能通过规定的方法访问数据
2.隐藏该类的实例细节,方便修改和实现
private 本类
默认 本类 同包
protected 本类 同包 子类
public 本类 同包 子类 其他
内部类的定义就是在另外一个类里面的类。与之对应,包括内部类的类也就称为外部类
内部类的作用
内部类分类
继承是类与类的一种关系,是一种“is a”的关系。比如狗继承动物,这里的动物类是狗类的父类或者基类,狗类是动物类的子类或者派生类
好处
子类拥有父类的所有属性与方法,但是由private修饰的属性子类是无法调用的,实现了代码的复用性
子类如果对于父类的方法不满意,认为不符合需求,我们可以自己编写所继承父类的方法,这种方式就成为代码的重写,当调用方法的时候会优先调用子类所重写的方法。
重写要注意,以下三个条件都是要保持一致的
方法的重载
在同一个类中处理不同数据的多个相同方法名的多态手段
父类对象属性初始化===》父类对象构造器方法===》子类对象属性初始化===》子类对象构造器方法
使用final关键字做标识由“最终的”含义
多态是对象的多种形态
Java中里的多态主要表现在两个方面
引用多态
父类的引用指向本类的对象
父类的引用指向子类的对象
方法多态
当我们父类的引用指向不同的子对象时,他们调用的方法也是多态的
创建本类对象,调用的方法为本类的方法
创建子类对象,调用的方法为子类重写的方法或继承的方法;
但是多态使用的时候应该注意:如果子类编写了一个父类不存在的方法,那么就不能通过父类的引用来调用这个方法
注意:继承是多态的基础
向上类型转换(隐式/自动类型转换),是小类类型转换到大类型
向下类型转换(强制类型转换),是大类型转换到小类型(有风险,可能出现数据溢出)
但是,如果父类没有引用该子类,那么是不能向下类型转换,虽然编译器不会报错,但是运行会出错。
还有一种情况是无法强制转换,父类引用时指向一个子类,之后又去强转为其他类中是不行的
instanceof运算符
instanceof是JAVA的一个二元运算符,和==,>,<是同一个类型,他的作用是测试它左边的对象是否是它右边类的实例,返回boolean类型的数据
定义:在类前使用abstract关键字修饰,则该类为抽象类
使用抽象类要注意以下几点
概念
接口可以理解为一个特殊的类,由全局变量和公共的抽象方法所组成
接口可以继承多个接口
如果说类是一种具体实现体,那么接口定义某一批类所遵循的规范,接口不关心这些类的内部数据,也不关心这些类的里面方法的实现细节,它只规定这些类里必须提供的某些方法
为什么要有接口
Java中一个类只能继承一个父类,是不够灵活的,可通过实现多个接口可以补充。
注意
如果要继承父类,继承父类必须在实现接口之前,即extends关键字必须在Implement关键字之前
接口在使用过程中经常和匿名内部类配合使用。匿名内部类就是没有名字的内部类,多用于关注实现而不关注实现类的名称的方法。
String
String类中使用final关键字修饰字符数组来保存字符串,所以String对象是不可变的
StringBuffer与StringBuilder
他们都是继承AbstractStringBuilder类。其中char[]没有被final关键字修饰,所以这两种对象都是可变的
线程安全
String中的对象是不可变的,可以理解为常量,线程安全。
StringBuffer对方法加入了同步锁,线程安全。
StringBuilder没有对方法进行加同步锁,所以是非线程安全的。
性能
String修改的时候都会需要新生成一个String对象,然后将指针指向新的String对象
StringBuffer和StringBuilder都会对自己操作,不会更改指针指向。StringBuilder的性能比StringBuffer好,但是冒着多线程不安全的风险
总结
装箱:将基本数据类型用他们对应的引用类包装起来
拆箱:将引用类型转换为基本数据类型
因为静态方法与非静态方法的声明周期不同,静态方法是随着类的加载而创建的,而非静态方法是随着类的实例化而创建的,静态方法不需要类的实例化也可以调用。所以静态方法里,不能调用其他非静态变量,也不可以访问非静态变量成员。
Java程序在执行子类的构造方法时候,会去调用父类特定的构造方法,如果没有,会去调用父类的空参构造方法。所以为了编译不报错,父类必须要存在无参构造方法。
语法层面上的区别
设计层面上的区别
抽象类是对类的一种抽象,接口是对类行为的一种抽象
在位置上看
成员变量存在类的大括号里面
局部变量存在方体体或静态代码块中
语法上看
二者都可以被final修饰
从变量在内存中的存储方式来看
从变量的生存周期来看
成员变量随着类的消亡而消失
局部变量随着方法的消亡而消失
是否能有初值
成员变量有默认值
局部变量没有默认值
对象实体是存储在堆内存,对象引用是存储在栈内存,一个对象可以被任意个对象引用所引用
帮助子类做初始化工作
==:
它的作用是判断两个对象的地址是否相等。
如果是基本数据类型直接比较值是否相等
如果是引用数据类型比较地址值是否相等
equals:
它的作用是判断两个对象是否相等,一般有两种情况
说明
hashCode
hashCode()的作用时获取哈希码,也被成为散列码;它实际上时返回一个Int整数。这个哈希码的作用时确定该对象在哈希表中索引的位置。HashCode()时定义在Object类中的,所以涉及到对象我们就会调用这个方法,而且这个方法是本地方法,该方法通常用来把对象的物理地址转换为整数之后返回
为什么重写equals时必须重写hashCode方法?
因为两个对象相等,则hashCode一定也是相同的。如果两个对象相等,这两个对象分别调用eqauls方法也返回true。但是两个对象有相同的hashcode值,也不一定是相等的。因此equals方法需要重写,则hashCode方法也必须被覆盖才能保证相等
为什么两个对象有相同的hashCode值,他们也不一定相等
因为hashCode()所使用的算法也许刚好会让多个对象传回的相同的值。例如在hashSet中hashCode只是用来缩小查找成本的
程序是含有指令和数据的文件,被存储在磁盘或其他数据存储设备中,也就是程序是静态的代码
进程是程序一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序是一个进行从创建、运行到消亡的过程。一个进程也就是一个执行中的程序,他在计算机中一个指令接着一个指令地执行,同时,每个进程还占着系统资源如CPU时间,内存空间,输入输出设备的使用权等等。换句话说,当程序在执行的时候,将会被操作系统挂入内存中。
NEW
初始状态,线程被构建,但是还没有调用start()方法
RUNNABLE
运行状态,Java线程将操作系统中的就绪状态和运行两种状态笼统的称作“运行中”
BLOCKED
阻塞状态,表示线程阻塞于锁
WAITING
等待状态,表示线程进入等待状态,进入该状态表示当前的线程需要等待其他线程做出一些特定动作(通知或中断)
TIME_WATING
超时等待状态,该状态不同于WAITING,它是可以在指定的时间自行返回的
TERMINATED
终止状态,表示当前线程已经执行完毕
线程比进程多了一个超时等待
创建、就绪、运行、阻塞、终止
final关键字主要用在三个地方:类,方法,变量
对于一个final变量,如果是基本数据类型的变量,则其数组一旦在初始化之后便不能再改变
如果是引用数据类型的变量,则在对其初始化之后便不能再让其指向另一个对象
当用final修饰一个类的时候,表明这个类不能被继承。final类中的所有成员方法都会被隐式的指定为final方法
当用final修饰一个方法的时候,表明这个方法不能被重写
在Java中,所有的异常都有一个共同的祖先是Throwable类。其中有两个子类Exception(异常)和Error(错误)。Exception能被程序本身处理(try…catch),Error是无法处理的(只能尽量避免)
Exception
程序本身可以处理的异常,可通过catch来进行捕获。Exception又可以分为受检查异常(必须处理)和不受检查异常(不必须处理)
不受检查异常
只有RuntimeException及其子类
受检查异常
除了RuntimeException及其子类之外的异常类
Error
Error的属于无法处理的错误,我们没有办法通过catch来进行捕获。例如,Java虚拟机运行错误、虚拟机内存不够、类定义错误。这些异常发生时,Java虚拟机一般会选择线程中止。
Throwable类常用方法
异常处理总结
Try块:用来捕获异常
Catch块:用于处理try捕获到的异常
Finally块:无论是否捕获或处理异常,finally块里的语句都会执行
以上三种情况时,finally块不会被执行
在try或finally用了System.exit(int)退出程序
所有线程死亡
关闭CPU
将Java对象转成二进制流写入磁盘,这个过程叫做序列化
Java中对象的序列化指的是将对象转换成字节序列的形式来表示,这些字节序列包含了对象的数据和信息,一个序列化的对象写到了数据库或者磁盘中,也可用于网络传输,其中我们的实体类实现Serializable接口,目的就是为了让其可序列化。
当然,序列化的目标就是为了反序列化,这样才可以把传输过来的二进制转化为本地java对象
如果不想被序列化那么在变量名前加transient关键字,其中的作用有两点
Scanner
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
sc.clone();
BufferReader
BUfferReader input = new BufferReader(new InputStreamReader(System.in));
String s = sc.nextLine();
按流向方向分:输入流、输出流
按操作单元分:字节流、字符流
按照担任角色分:节点流和处理流
输入流和输出流
读文件输入流,写文件输出流
字节流和字符流
字节流是数据单位为8位的字节,字符流操作的是数据单位为16位的字符
为什么要字符流
Java中字符采用的是Unicode标准,在Unicode标准下,一个英文字母为一个字节,一个中文是两个字节。如果字节流一个一个读会出现乱码,有字符流才会在缓冲区根据编码规则进行编码对应的字符
节点流和处理流
节点流:直接操作数据的读写的流类
处理流:对一个已存在的流的链接和封装,通过对数据进行处理为程序提供功能强大、灵活的读写功能。
在诸多的处理流中,缓冲流非常重要。为了减少程序与磁盘的交互,但是如果其中长度超过输出缓冲区的大小,刷新输出缓冲区,然后直接写数据
BIO
同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待完成。在活动连接数不是特别高(小于单机1000)的情况,这种模式还是比较不错的,可以让每一个连接专注于自己的I/O并且编程模型简单,也不用过多考虑系统过载、限流等问题。
NIO
同步非阻塞I/O模型,NIO提供了SocketChannel和ServerSocketChannel两种不同的套接字通道实现。这两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模型正好与之相反。对于低负载、低并发的应用程序,可使用同步阻塞I/O来提升开发速度和更好的维护性;对于高负载、高并发的应用,应使用NIO的非阻塞模式来开发。
AIO
在Java7中引入,它是异步非阻塞的I/O模型。异步的IO是基于事件和回调机制的实现的,也就是应用操作之后会直接返回,不会阻塞在那里,当后台处理完成后,操作系统会通知相应的线程进行后续的操作。
浅拷贝:对基本数据类型进行值传递,对引用数据类型进行地址拷贝。
深拷贝:对基本数据类型进行值传递,对引用数据类型创建一个新的对象,并赋值其内容。
反射机制就是采用动态加载,我们通过三种方法获得Class:
Object类的getClass()方法
Class class = 对象名.getClass()
类的静态属性
Class class=类名.class
Class类的静态方法
Class class = Class.forName(“类的正名”);
正名:包类路径名,如:cn.itcast.bean.Student
获得Class后,我们就可以调用Class对象的newInstance()方法来创建Class对象对应类的实例了,或者通过获得构造器(类中一定要有空参构造),给构造器传入参数,也可以创建实例
数组:在内存中,数组是一块连续的区域,随机查找快,插入数据和删除数据效率低,插入数据时吗,这个位置后面的数据在内存中都要全部向后移动一位。删除数据时,这个位置的后面数据都要全部向前移动一位
链表:在内存中可以存在任意地方,不要求连续。增加数据和删除效率高,新增数据,直接将尾节点指向新增节点即可,删除数据的话,把尾指针指向下一个几点即可,但是查询数据效率很低,需要从头指针一个一个的查询下去!
在静态方法中,我们可以直接类名.方法名()即可调用,要注意的是,静态方法中是不可以访问非静态变量和方法的.
静态变量是被所有的对象共享,在内存中只有一个副本(存在方法区)只能在类初次加载的时候才会被初始化
只需要执行一次的初始化操作都放在static代码块中进行,为了优化程序性能。
减少字符输入量,提高代码的可阅读性,以便更好的理解程序
Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤、映射数据等操作
特点