(目前有很多未完善的地方,阿超持续更新中…)
面向对象深刻理解
面向对象有什么好处
举个例子:
《大话设计模式》中大鸟给小菜讲的故事非常经典:
“三国时期,曹操带领百万大军攻打东吴,大军在长江赤壁驻扎,军船连成一片,眼看就要灭掉东吴,统一天下,曹操大悦,于是大宴众文武,在酒席间,曹操诗性大发,不觉吟道:‘喝酒唱歌,人生真爽……’于是一臣子速命印刷工匠刻版印刷,以便流传天下。”
“样版出来给曹操一看,曹操感觉不妥,说道:‘喝酒唱歌,此话过俗,应改为‘对酒当歌’较好!’于是此臣就命工匠重新来过。工匠眼看连夜刻版之工,彻底白费,心中叫苦不迭。只得照办。”
“样版再次出来请曹操过目,曹操细细一品,觉得还是不好,说:‘人生真爽‘太过直接,应改问语才够意境,因此应改为‘对酒当歌,人生几何……’当臣子转告工匠之时,工匠晕倒……”
“这里面问题出在哪里?”
“就是因为三国时期活字印刷还未发明,所以要改字的时候,就必须要整个刻板全部重新刻。”
“说得好!如果是有了活字印刷,则只需更改四个字就可,其余工作都未白做。岂不妙哉。
一、只需要更改要改的字,此为可维护;
二、这些字并非用完这次就无用,完全可以在后来的印刷中重复使用,此乃可复用;
三、此诗若要加字,只需另刻字加入即可,这是可扩展;
四、字的排列其实可能是竖排可能是横排,此时只需将活字移动就可做到满足排列需求,这就是灵活性好。”
“而在活字印刷术出现之前,上面的四种特性都无法满足,要修改,必须重刻,要加字,必须重刻,要重新排列,必须重刻,印完这本书后,此版已无任何可再利用价值。”
面向对象的三大特性:
- 1、封装
隐藏对象的属性和实现细节,仅对外提供公共访问方式,将变化隔离,便于使用,提高复用性和安全性。 - 2、继承
提高代码复用性;继承是多态的前提。 - 3、多态
父类或接口定义的引用变量可以指向子类或具体实现类的实例对象。提高了程序的拓展性。
六大基本原则
- 1、单一职责原则SRP(Single Responsibility Principle):
? 两个不同的功能不能放在同一个类里,随着功能的增多,类会越来越大,代码也越来越复杂,耦合度太强
- 2、开放封闭原则OCP(Open-Close Principle):
? 对象(类、模块、函数等)对于扩展是开放的,对于修改是封闭的
开闭原则指导我们,当软件需要变化时,应该尽量通过扩展的方式来实现变化,而不是通过修改已有的代码来实现。这里的“应该尽量”4个字说明OCP原则并不是说绝对不可以修改原始类的,当有这种修改的需求时,应该尽早地重构,而不是通过继承等方式添加新的实现,这会导致类型的膨胀以及历史遗留代码的冗余
- 3、里式替换原则LSP(the Liskov Substitution Principle LSP)
子类可以替换父类出现在父类能够出现的任何地方。比如你能代表你爸去你奶奶家干活。
里氏替换原则的核心原理是抽象,抽象又依赖于继承这个特性,在OOP(面向对象的编程)当中,继承的优缺点都相当明显。 优点如下:
· (1)代码重用,减少创建类的成本,每个子类都拥有父类的方法和属性;
· (2)子类与父类基本相似,但又与父类有所区别;
· (3)提高代码的可扩展性。
继承的缺点:
· (1)继承是侵入性的,只要继承就必须拥有父类的所有属性和方法;
· (2)可能造成子类代码冗余、灵活性降低,因为子类必须拥有父类的属性和方法。
-
4、依赖倒置原则DIP(the Dependency Inversion Principle DIP) 高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。就是你出国要说你是中国人,而不能说你是哪个村子的。比如说中国人是抽象的,下面有具体的xx省,xx市,xx县。你要依赖的是抽象的中国人,而不是你是xx村的。 -
5、接口分离原则ISP(the Interface Segregation Principle ISP) 设计时采用多个与特定客户类有关的接口比采用一个通用的接口要好。就比如一个手机拥有打电话,看视频,玩游戏等功能,把这几个功能拆分成不同的接口,比在一个接口里要好的多。
接口隔离原则的目的是系统解开耦合,从而容易重构、更改和重新部署
迪米特法则又叫最少知识原则,一个对象应当对其他对象有尽可能少的了解。再复杂的系统都可以为用户提供一个简单的门面,Java Web开发中作为前端控制器的Servlet或Filter就是一个门面,浏览器对服务器的运作方式一无所知,但是通过前端控制器就能够根据你的请求得到相应的服务。调停者模式也可以举一个简单的例子来说明,例如一台计算机,CPU、内存、硬盘、显卡、声卡各种设备需要相互配合才能很好的工作,但是如果这些东西都直接连接到一起,计算机的布线将异常复杂,在这种情况下,主板作为一个调停者的身份出现,它将各个设备连接在一起而不需要每个设备之间直接交换数据,这样就减小了系统的耦合度和复杂度。 迪米特法则简单的说就是如何做到"低耦合",门面模式和调停者模式就是对迪米特法则的践行。(例子:皇上召见大臣是通过太监)
总结
-
单一职责原则:一个类只负责一个功能 -
开闭原则:对象**(**类,模块,函数等等)对于扩展开放,对于修改关闭 -
里氏代换原则:能够使用到父类的地方都能够使用子类对象,就是子类可以替换父类出现在父类能够出现的任何地方 -
依赖倒置原则:高层模块不应该依赖低层模块,它们都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。 -
接口隔离原则:客户端不应该依赖它不需要的接口(功能),类与类之间的依赖应该建立在最小的接口上 -
迪米特法则: 一个对象应当对其它对象有尽可能少的了解,只和朋友通信,不和陌生人说话,所以迪米特法则又叫做最少知识原则
高内聚低耦合:
高内聚是指一个软件模块是由相关性很强的代码组成,只负责一项任务,也就是常说的单一职责原则。
模块之间联系越紧密,其耦合性就越强,模块的独立性则越差。
对于低耦合,粗浅的理解是:一个完整的系统,模块与模块之间,尽可能的使其独立存在。也就是说,让每个模块,尽可能的独立完成某个特定的子功能。模块与模块之间的接口,尽量的少而简单。如果某两个模块间的关系比较复杂的话,最好首先考虑进一步的模块划分。这样有利于修改和组合。
面向对象和面向过程的区别
举个最简单点的例子来区分 面向过程和面向对象
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。他的缺点在于不易维护,不易复用,不易拓展
有一天你想吃鱼香肉丝了,怎么办呢?你有两个选择
1、自己买材料,肉,鱼香肉丝调料,蒜苔,胡萝卜等等然后切菜切肉,开炒,盛到盘子里。这就是面向过程
2、去饭店,张开嘴:老板!来一份鱼香肉丝!这是面向对象。
面向对象的优势
首先你不需要知道鱼香肉丝是怎么做的,降低了耦合性。如果你突然不想吃鱼香肉丝了,想吃羊肉泡馍,对于1你可能不太容易了,还需要重新买菜,买调料什么的。对于2,太容易了,大喊:老板!那个鱼香肉丝换成羊肉泡馍吧,提高了可维护性。总的来说就是降低耦合,提高维护性!
面向过程是具体化的,流程化的,解决一个问题,你需要一步一步的分析,一步一步的实现。
面向对象是模型化的,你只需抽象出一个类,这是一个封闭的盒子,在这里你拥有数据也拥有解决问题的方法。需要什么功能直接使用就可以了,不必去一步一步的实现,至于这个功能是如何实现的,不管我们的事,我们会用就可以了。
面向对象的底层其实还是面向过程,把面向过程抽象成类,然后封装,方便我们使用的就是面向对象了。
面向过程:
- 优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源,比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发,性能是最重要的因素
- 缺点:不易维护、不易复用、不易扩展
面向对象:
- 优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护
- 缺点:性能比面向过程低
总结一下我对面向对象的理解:面向对象的编程方式使得每一个类都只做一件事。面向过程会让一个类越来越全能,就像一个管家一样做了所有的事。而面向对象像是雇佣了一群人,每个人只一件事
Java语?和其他语?区别
- 一处编译,多处运行(Java 虚拟机实现平台?关性)
- 健全的安全体系
- 兼容不同平台
- 自带内存管理机制
- 支持多线程(C++ 语?没有内置的多线程机制,因此必须调?操作系统的多线程功能来进?多线程程序设计)
- 属于解释型语言(C语言是编译型语言,C中有指针的概念,java取消了指针的概念)
Java和C++的区别
都是面向对象的语言,都支持封装、继承和多态
Java不提供指针来直接访问内存,程序内存更加安全
Java的类是单继承的,C++支持多重继承;虽然Java的类不可以多继承,但是接口可以多继承。
Java有自动内存管理机制,不需要程序员手动释放无用内存
JRE、JDK、JVM区别
-
JDK:java 开发工具。是功能?全的 Java SDK。它拥有 JRE 所拥有的?切,还有编译器(javac)和?具(如 javadoc 和 jdb)。它能够创建和编译程序 -
JRE: java运行时环境。它是运?已编译 Java 程序所需的所有内容的集合,包括 Java 虚拟机(JVM),Java 类库,java 命令和其他的?些基础构件 -
JVM:Java 虚拟机,是运? Java 字节码的虚拟机。JVM 有针对不同系统的特定实现(Windows,Linux,macOS),?的是使?相同的字节码,它们都会给出相同的结果
简单理解:JDK=JRE(包含JVM+核心类库(JavaAPI))+开发工具
JDK1.8之前和JDK1.8之后接口不同
先来回顾一下什么是接口,接口指系统对外提供的所有服务(Interface定义的实实在在的接口,即接口类型)【只能有抽象方法】 的入口,是一个抽象类型。一个类通过实现接口的方式,从而继承接口的抽象方法;一个类只能继承一个类,但可以继承多个接口;一个接口不能实现另一个接口,但可以继承多个其他接口
JDK1.8之前:
1.接口中的变量都是静态变量(public static final),必须显式初始化
2.接口中所有方法默认都是public abstract
3.接口没有构造方法,不可以被实例化,但可以被实现(常作为类型使用,也就是父类引用指向子类对象)
4.实现类必须实现接口的所有的方法
5.实现类可以实现多个接口(java中的多继承)
? ? JDK1.8之后: ? 1.接口里可以有(default关键字修饰的)默认方法(方法体)了 ? 默认方法可以被继承,通过实例调用,可以有多个。如果一个类实现了多个接口,多个接口都定义了多个同样的默认方法时就需要实现类覆盖重写接口中的默认方法,不然会报错,可以使用super来调用指定接口的默认方法。 ? ? 2.接口里可以声明(并且可以提供实现)静态方法 ? 接口中的静态方法必须是public的,public修饰符可以省略,static修饰符不能省略,静态方法不能被继承即覆盖,所以只被具体所在的接口调用,接口中静态方法可以有多个。 ?
简单来说:JDK1.8之前接口只能有抽象?法,JDK1.8之后接口中可以有不同?法,但是?法必须?static或者default来修饰
接口和抽象类区别
-
相同点:
- 都代表系统的抽象层;都不能被实例化;都能包含抽象方法(用于描述系统提供的服务,不必提供具体实现)
-
不同点:
- 一个类只能继承一个直接父类,但可以实现多个接口;
- 抽象类有构造器 接口没有构造器;抽象类中可以有普通?法 接口中有没有要区分JDK版本;
- 抽象类中成员变量??定义权限修饰 接口成员变量默认为public static final;
- 从设计层?来说,抽象是对类的抽象,是?种模板设计,?接?是对?为的抽象,是?种?为的规范
Java中的常用容器有哪些
数据容器主要分为了两类,Collection:(存放独立元素的序列)和Map(存放key-value型的元素对)
常用的容器有:
ArrayList:其数据结构采用的是线性表,此种结构的优势是访问和查询十分方便,但添加和删除的时候效率很低。
LinkedList :其数据结构采用的是链表,此种结构的优势是删除和添加的效率很高,但随机访问元素时效率较ArrayList类低。
HashSet: Set类不允许其中存在重复的元素(集),无法添加一个重复的元素(Set中已经存在)。HashSet利用Hash函数进行了查询效率上的优化,其contain()方法经常被使用,以用于判断相关元素是否已经被添加过
HashMap: 提供了key-value的键值对数据存储机制,可以十分方便的通过键值查找相应的元素,而且通过Hash散列机制,查找十分的方便。
throw和throws的区别
throws:
跟在方法声明后面,后面跟的是异常类名,可以跟多个异常类名,用逗号隔开,表示抛出异常,由该方法的调用者来处理,throws表示有出现异常的可能性,并不一定出现这些异常
throw:
用在方法体内,后面跟的是异常类对象名,只能抛出一个异常对象名,表示抛出异常,由该方法体内的语句来处理,throw则是抛出了异常,执行throw一定出现了某种异常
final、finally、finalize区别,怎么使用
-
final可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量表示该变量是一个常量不能被重新赋值 -
finally一般作用在try-catch代码块中,在处理异常的时候,通常我们将一定要执行的代码方法写在 finally代码块中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码 -
finalize是一个方法,属于Object类的一个方法,而Object类是所有类的父类,该方法一般由垃圾回收器来调用,当我们调用System.gc() 方法的时候,由垃圾回收器调用finalize(),回收垃圾,对一个对象是否可回收做的最后判断
局部变量和成员变量区别
作用域
存储位置
生命周期
初始值
-
成员变量:有默认初始值 -
局部变量:没有默认初始值,使用前必须赋值
使用原则
- 在使用变量时需要遵循的原则为:就近原则,首先在局部范围找,有就使用;接着在成员位置找
值传递和引用传递区别
java都是引用传递
对于基本数据类型,传递是值的副本,而不是值本身。
对于对象类型,传递是对象的引用,当在一个方法操作参数的时候,其实操作的是引用所指向的对象。
创建对象在JVM中的位置
虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用表的类是否已被加载,解析和初始化过。如果没有,那必须先执行相应的类加载过程。在类加载检查通过后,接下来虚拟机将为新生对象分配内存。
==和equals区别
String中的equals方法是被重写过的,因为object的equals方法是比较的对象的内存地址,而String的equals方法比较的是对象的值。
当创建String类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个String对象。
Hashcode和equals的区别
hashCode介绍
它实际上是返回一个int整数
这个哈希码的作用是确定该对象在哈希表中的索引位置
hashCode() 定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode() 函数
equals介绍
- 若重写了equals(Object obj)方法,则有必要重写hashCode()方法
- 若两个对象equals(Object obj)返回true,则hashCode()也返回相同的哈希码值
- 若两个对象equals(Object obj)返回false,则hashCode()不一定返回不同的哈希码值
- 若两个对象hashCode()返回相同哈希码值,则equals(Object obj)不一定返回true
- 若两个对象hashCode()返回不同哈希码值,则equals(Object obj)一定返回false
- 同一对象在执行期间若已经存储在集合中,则不能修改影响hashCode值的相关信息,否则会导致内存泄露问题
重载和重写区别
构造器不能被继承,因此不能被重写,但可以被重载
方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。
**重载:**发生在同一个类中,方法名相同参数列表不同(参数类型不同、个数不同、顺序不同),与方法返回值和访问修饰符无关,即重载的方法不能根据返回类型进行区分
**重写:**发生在父子类中,方法名、参数列表必须相同,返回值小于等于父类,抛出的异常小于等于父类,访问修饰符大于等于父类(里氏代换原则);如果父类方法访问修饰符为private则子类中就不是重写。
包装类和基本类区别
1、包装类是一个类,拥有方法和属性2、包装类是引用的传递,而基本类是值的传递3、包装类需要使用new关键字创建对象,基本类不需要4、基本数据类型存储在虚拟机栈的局部变量表中,而包装类存储在Java堆中5、基本数据类型的初始值是0值,整形是0,浮点型是0.0,boolean是false,而包装类初始值是null
Integer是否可以被继承?为什么
不能因为是用final修饰的,Integer 继承 Number 抽象类,实现了 Comparable 接口。Number 类是常用数字类型类的公共父类,它规定了其子类(通常就是数字类)必须提供将其值转换成 int、long、float、double、byte、short 类型数据的能力。实现 Comparable 接口自然是为了比较大小。另外,Integer 类型也是最终类,不可被继承(事实上,常用数据类型的封装类都是 final 类)。
JDK1.8之后有哪些新特性
1. default关键字: 在接口中引入了新的关键字default,通过使用default修饰方法,可以让我们在接口里面定义具体的方法实现2. Lambda表达式:这是一个重要的更新,这意味着 java也开始承认了函数式编程,大大简化了代码的开发3. Date Api更新:加强对日期与时间的处理。4. map集合中红黑树:原来的hashMap采用的数据结构是哈希表 (数组+链表),在1.8之后,在数组+链表+红黑树来实现hashmap,当碰撞的元素个数大于8时 & 总容量大于64,会有红黑树的引入 5. 并行流和串行流:在jdk1.8新的stream包中针对集合的操作也提供了并行操作流和串行操作流。并行流就是把内容切割成多个数据块,并且使用多个线程分别处理每个数据块的内容。Stream api中声明可以通过parallel()与sequential()方法在并行流和串行流之间进行切换。
如何解决Hash冲突问题
开放地址
法(线性探测再散列,二次探测再散列,伪随机探测再散列)
再哈希法
拉链法(Java hashmap就是这么做的)
建立一个公共溢出区
ArrayList和LinkedList的区别
LinkedList首部插入数据很快,因为只需要修改插入元素前后节点的prev值和next值即可
ArrayList首部插入数据慢,因为数组复制的方式移位耗时多
LinkedList中间插入数据慢,因为遍历链表指针(二分查找)耗时多
ArrayList中间插入数据快,因为定位插入元素位置快,移位操作的元素没那么多
LinkedList尾部插入数据慢,因为遍历链表指针(二分查找)耗时多
ArrayList尾部插入数据快,因为定位速度快,插入后移位操作的数据量少
线程创建4种方式
- 继承Thread类
- 实现Rannable接口
- 实现Callable接口
- 线程池中获取
并发和并行有什么区别
-
并发是指一个处理器同时处理多个任务。 -
并行是指多个处理器或者是多核的处理器同时处理多个不同的任务。 来个比喻: ? 现在有一台咖啡机在售卖咖啡,这时候有很多客人都在购买咖啡,这时候对于用户购买咖啡来说,就是并发行为,因为咖啡机同时只能给一名客人出售咖啡,其他客人只能够排队等待。这个过程就叫并发,而在我们开发中,操作系统可能只有一个cpu处理器(即我们的咖啡机),这时候就只能处理一个线程,而我们则会启动多个线程(多个购买咖啡的用户)。这个过程就是我们并发。而并发数指的就是同时有多少的线程存在 并发就是同一时刻中,只有一个线程在执行。 ? 还是以咖啡机为例,一台咖啡机明显不够使用了,这个时候又增加一台咖啡机,客人可以同时在在两台咖啡机下购买咖啡,这个过程,就是并行,两台咖啡机同时工作,不像一台咖啡机,只能一台工作,这样齐头并进,便是 并行。在开发中,有的设备的配置比较高级,有多个cpu,可以同时运行多个线程,也即是并行 并行就是,在同一时间内,有个多线程在执行。 同一时刻能同时进行不同的任务,看到的是同一个时间点上有多少个任务在执行,这个执行的数量叫做并发度 并发是交替执行不同的任务,是在一个时间段上有多少个任务执行,这个执行数量叫并发数
为什么要使用线程池
线程和数据库连接这些资源都是非常宝贵的资源。那么每次需要的时候创建,不需要的时候销毁,是非常浪费资源的。那么我们就可以使用缓存的策略,也就是使用线程池。 第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控
如何解决线程安全问题
加锁
线程的生命周期
-
New 尚未启动的线程的线程状态 -
Runnable 可运行线程的线程状态,等待CPU调度 -
Blocked 线程阻塞等待监视器锁定的线程状态(处于synchronized同步代码块或方法中被阻塞) -
Waiting 等待线程的线程状态 ? (不带超时的方式:Object.wait、Thread.join、LockSupport.park) -
Timed Waiting 具有指定等待时间的等待线程的线程状态 ? (带超时的方式:Thread.sleep、Object.wait、Thread.join、LockSupport.parkNanos、LockSupport.parkUnitl) -
Terminated 终止线程的线程状态。(线程正常完成执行或出现异常)
Java 中常用的设计模式?说说工厂模式或者几种比较熟悉的说一下
1.单例(Singleton)模式:某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。2.原型(Prototype)模式:将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似的新实例。3.工厂方法(Factory Method)模式:定义一个用于创建产品的接口,由子类决定生产什么产品。4.抽象工厂(AbstractFactory)模式:提供一个创建产品族的接口,其每个子类可以生产一系列相关的产品。5.建造者(Builder)模式:将一个复杂对象分解成多个相对简单的部分,然后根据不同需要分别创建它们,最后构建成该复杂对象。6.代理(Proxy)模式:为某对象提供一种代理以控制对该对象的访问。即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。7.适配器(Adapter)模式:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。8.桥接(Bridge)模式:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。9.装饰(Decorator)模式:动态的给对象增加一些职责,即增加其额外的功能。10.外观(Facade)模式:为多个复杂的子系统提供一个一致的接口,使这些子系统更加容易被访问。11.享元(Flyweight)模式:运用共享技术来有效地支持大量细粒度对象的复用。12.组合(Composite)模式:将对象组合成树状层次结构,使用户对单个对象和组合对象具有一致的访问性。13.模板方法(TemplateMethod)模式:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。14.策略(Strategy)模式:定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的改变不会影响使用算法的客户。15.命令(Command)模式:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。16.职责链(Chain of Responsibility)模式:把请求从链中的一个对象传到下一个对象,直到请求被响应为止。通过这种方式去除对象之间的耦合。17.状态(State)模式:允许一个对象在其内部状态发生改变时改变其行为能力。18.观察者(Observer)模式:多个对象间存在一对多关系,当一个对象发生改变时,把这种改变通知给其他多个对象,从而影响其他对象的行为。19.中介者(Mediator)模式:定义一个中介对象来简化原有对象之间的交互关系,降低系统中对象间的耦合度,使原有对象之间不必相互了解。20.迭代器(Iterator)模式:提供一种方法来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。21.访问者(Visitor)模式:在不改变集合元素的前提下,为一个集合中的每个元素提供多种访问方式,即每个元素有多个访问者对象访问。22.备忘录(Memento)模式:在不破坏封装性的前提下,获取并保存一个对象的内部状态,以便以后恢复它。23.解释器(Interpreter)模式:提供如何定义语言的文法,以及对语言句子的解释方法,即解释器。
char 型变量中能不能存储一个中文汉字?为什么
char型变量是用来存储Unicode编码的字符的,unicode编码字符集中包含了汉字,所以,char型变量中当然可以存储汉字啦。不过,如果某个特殊的汉字没有被包含在unicode编码字符集中,那么,这个char型变量中就不能存储这个特殊汉字。补充说明:unicode编码占用两个字节,所以,char类型的变量也是占用两个字节。
TCP与UDP的区别
- TCP是面向连接的协议,而UDP是无连接的协议。即TCP面向连接;UDP是无连接的,即发送数据之前不需要建立连接
- TCP 提供交付保证(Tcp通过校验和,重传控制,序号标识,滑动窗口、确认应答实现可靠传输),无差错,不丢失,不重复,且按序到达,也保证了消息的有序性。该消息将以从服务器端发出的同样的顺序发送到客户端,尽管这些消息到网络的另一端时可能是无序的。TCP协议将会为你排好序。
UDP不提供任何有序性或序列性的保证。UDP尽最大努力交付,数据包将以任何可能的顺序到达。 TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道 - UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信
- TCP首部开销20字节; UDP的首部开销小,只有8个字节
- TCP速度比较慢,而UDP速度比较快,因为TCP必须创建连接,以保证消息的可靠交付和有序性,毕竟TCP协议比UDP复杂
- UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
- TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;
UDP是面向报文的 - TCP对系统资源要求较多,UDP对系统资源要求较少。
TCP被认为是重量级的协议,而与之相比,UDP协议则是一个轻量级的协议。因为UDP传输的信息中不承担任何间接创造连接,保证交货或秩序的的信息。这也反映在用于承载元数据的头的大小 - 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信 。基于UDP不需要建立连接,所以且适合多播的环境,UDP是大量使用在游戏和娱乐场所
TCP和udp的优缺点
UDP :
优点:简单、传输快 (1)网速的提升给UDP的稳定性提供可靠网络保障,丢包率很低,如果使用应用层重传,能够确保传输的可靠性。 (2)TCP为了实现网络通信的可靠性,使用了复杂的拥塞控制算法,建立了繁琐的握手过程,由于TCP内置的系统协议栈中,极难对其进行改进。采用TCP,一旦发生丢包,TCP会将后续的包缓存起来,等前面的包重传并接收到后再继续发送,延时会越来越大,基于UDP对实时性要求较为严格的情况下,采用自定义重传机制,能够把丢包产生的延迟降到最低,尽量减少网络问题对游戏性造成影响。
缺点:不可靠,不稳定;
UDP应用场景: 1.面向数据报方式 2.网络数据大多为短消息 3.拥有大量Client 4.对数据安全性无特殊要求 5.网络负担非常重,但对响应速度要求高
TCP: 优点:可靠 稳定 TCP的可靠体现在TCP在传输数据之前,会有三次握手来建立连接,而且在数据传递时,有确认. 窗口. 重传. 拥塞控制机制,在数据传完之后,还会断开来连接用来节约系统资源。
缺点:慢,效率低,占用系统资源高,易被攻击
TCP应用场景: 当对网络质量有要求时,比如HTTP,HTTPS,FTP等传输文件的协议;POP,SMTP等邮件传输的协议
并行和并发有什么区别
并发:多个任务在同一个CPU核上,按细分的时间片轮流执行,从逻辑上看任务是同时执行的;并行:多个处理器或多核处理器同时处理多个任务。两者区别:并发是交替执行,并行是同时执行
线程和进程的区别
-
进程:进程是运行在操作系统上的一个应用程序 -
线程:线程就是进程中的一个任务 例如: ? 打开微信聊天工具就是开启了一个进程 ? 在微信中和其中的一个人聊天就会开启一个线程
怎么判断对象是否可以被回收
- **引用计数器法:**为每个对象创建一个引用计数,有对象引用时计数器 +1,引用被释放时计数 -1,当计数器为 0 时就可以被回收。它有一个缺点不能解决循环引用的问题;
- **可达性分析算法:**从 GC Roots作为起点,引用链作为路径。当一个对象到 GC Roots没有任何引用链相连时,则证明此对象是可以被回收的。
说说垃圾回收算法的底层原理?(新生代、老年代)
标记清除 首先标记出所有需要回收的对象,在标记完成后统一回收掉被标记的对象 (老年代)
标记复制 将可用内存按容量划分为大小相等的两块,每次使用其中的一块,这一块用完了就将还存活者的对象复制到另一块上面 (新生代)
标记整理 让所有存活的对象都移向内存空间的一端,然后直接清理掉边界以外的内存 (老年代)
垃圾回收器的作用
释放和重用资源 是垃圾回收算法的具体实现
**Serial收集器(复制算法):**新生代单线程收集器,标记和清理都是单线程,优点是简单高效; **ParNew收集器 (复制算法):**新生代收并行集器,实际上是Serial收集器的多线程版本,在多核CPU环境下有着比Serial更好的表现; **Parallel Scavenge收集器 (复制算法):**新生代并行收集器,追求高吞吐量,高效利用 CPU。吞吐量 = 用户线程时间/(用户线程时间+GC线程时间),高吞吐量可以高效率的利用CPU时间,尽快完成程序的运算任务,适合后台应用等对交互相应要求不高的场景;
**Serial Old收集器 (标记-整理算法):**老年代单线程收集器,Serial收集器的老年代版本; Parallel Old收集器 (标记-整理算法): 老年代并行收集器,吞吐量优先,Parallel Scavenge收集器的老年代版本; CMS(Concurrent Mark Sweep)收集器(标记-清除算法): 老年代并行收集器,以获取最短回收停顿时间为目标的收集器,具有高并发、低停顿的特点,追求最短GC回收停顿时间
G1(Garbage First)收集器 (标记-整理算法): Java堆并行收集器,G1收集器是JDK1.7提供的一个新收集器,G1收集器基于“标记-整理”算法实现,也就是说不会产生内存碎片
break、continue、return的区别及作用
-
break 跳出总上一层循环,不再执行循环(结束当前的循环体) -
continue 跳出本次循环,继续执行下次循环(结束正在执行的循环 进入下一个循环条件) -
return 程序返回,不再执行下面的代码(结束当前的方法 直接返回)
如有不足还请各位多多指教
|