java面试-基础总结

java基础面试

在面试阶段是一个自我提升的最好时间,以前总认为基础知识没有那么重要,所以每次面试的时候都会临时背一下java基础。我是那种不理解意思也可以流利的背下来的那种,自我感觉理科的知识背下来是没有灵魂的,但是怎么办,做为一个女程序员,入门的过程还是比较难受的,先坚持下来,然后在实践中慢慢去理解去深入。总的来说java基础还是挺重要的,当你觉得其不重要的时候可能就是真正的进入到脑袋里了。以下是我总结的有关的面试经验的整合,百变不离其中,好好准备吧,祝各位小仙女小仙子早日找到心仪的工作哦。

一.Java修饰符及各自使用的机制

(public,abstract,final,synchronized,super)
答案:
public:public表明该数据成员、成员函数是对所有用户开放的,所有用户都可以直接进行调用。
private:private表示私有,私有的意思就是除了 class自己之外,任何人都不可以直接使用。
protected:protected对于子女、朋友来说,就是 public的,可以自由使用,没有任何限制,而对于其他的外部 class,protected就变成 private。
Abstract:可以用于类、方法、属性、事件和索引指示器(indexer),表示其为抽象成员,抽象方法是没有方法体的方法。abstract不可以和 static、virtual、final、native一起使用,声明为 abstract成员可以不包括实现代码,但只要类中还有未实现的抽象成员(抽象方法),那么这个类就是一个抽象类,抽象类的对象就不能被实例化,通常用于强制继承类必须实现某一成员.
抽象类是必须要派生子类的。并且,如果子类没有实现抽象基类的所有方法,则子类也成为一个抽象类。
Synchronized:synchronized关键字,代表这个方法加锁,相当于不管哪一个线程(例如线程 A),运行到这个方法时,都要检查有没有其它线程 B(或者 C、 D等)正在用这个方法(或者该类的其他同步方法), 有的话要等正在使用 synchronized方法的线程 B(或者 C 、D)运行完这个方法后再运行此线程 A,没有的话,锁定调用者,然后直接运行。它包括两种用法:synchronized方法和 synchronized块。
Super:在 JAVA类中使用 super来引用父类的成分,用 this来引用当前对象,如果一个类从另外一个类继承,我们 new这个子类的实例对象的时候,这个子类对象里面会有一个父类对象。怎么去引用里面的父类对象呢?使用 super来引用,this指的是当前对象的引用,super是当前对象里面的父对象的引用。

二.Java服务器端常用的垃圾回收算法

1.Mark-Sweep(标记-清除)算法
2.Copying(复制)算法
3.Mark-Compact(标记-整理)算法
4.Generational Collection(分代收集)算法

三.java常用包相关问题

1)Char能不能储存一个汉字,为什么?
2)举例出Java中常用的包?
第一个包:java.lang包。该包提供了Java语言进行程序设计的基础类,它是默认导入的包。该包里面的Runnable接口和Object、Math、String、StringBuffer、System、Thread以及Throwable类需要重点掌握,因为它们应用很广。
第二个包:java.util包。该包提供了包含集合框架、遗留的集合类、事件模型、日期和时间实施、国际化和各种实用工具类(字符串标记生成器、随机数生成器和位数组)。
第三个包:java.io包。该包通过文件系统、数据流和序列化提供系统的输入与输出。
第四个包:java.net包。该包提供实现网络应用与开发的类。
第五个包:java.sql包。该包提供了使用Java语言访问并处理存储在数据源(通常是一个关系型数据库)中的数据API。

四.重载和重写的区别

(方法的重载和重写)
一、方法重写(Override):在 Java中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。
规则:“两同两小一大”:
1.“两同”:即方法名相同,形参列表相同;
2.“两小”:指的是子类方法返回值类型与方法声明抛出的异常类要比父类方法更小或相等,因为子类可以解决父类的一些问题,不能比父类有更多的问题;列如,父类的一个方法申明了一个检查异常 IOException,在重写这个方法时就不能抛出 Exception,只能抛出 IOException的子类异常。
3.“一大”:指的子类方法的访问权限应该比父类的更大或相等;
注意: 1.方法的重写,在一般情况下,返回自类型、方法,名,形参列表,访问权限,抛出的异常,都应该保持一致; 2.被覆盖的方法不能为 private,否则在其子类中只是定义了一个方法,并没有对其进行覆盖。
二、方法重载(Overload): java允许同一个类里定义多个同名的方法,只要形参列表不同即可。如果一个类中包含了两个或两个以上的方法名相同,但参数列表不同,则被称为方法重载。
规则:“两同,一个不同”:
1.”两同“:即同一个类中、方法名相同;2.“一个不同”:即形参列表不同;
注意:方法的重载只跟方法名、参数列表有关,与方法其他部分,如返回值类型、修饰符等无关。

五.泛型

(泛型是为了避免类型强转问题)
当返回参数类型不确定的时候使用泛型,而且可以省去object的强转过程。
5)传值和传引用的区别?
1、传值:传值就是指将一个值传递到方法的内部。例如int a = 5,那么也就是给int型变量a赋值,值为5.如果一个方法,将这个变量传进方法的内部,则进行的就是传值。在java中,有8种基本数据类型,它们分别为:int、long、float、double、char、boolean、short、byte.这8种基本的数据类型作为参数进行传递是,都是进行的传值。·除此之外,还有一种特殊的情况,String。本身String是一个引用类型,很多人认为在向方法中传递String类型参数时,是进行传引用。其实在这里,String可以看做为一个包装类,因为String其本身就是通过字符数组实现的,那么它在实现参数传递的时候,也就是以char型数据的方式进行的,也就是进行传值。
2、传引用:java中的引用可以初步的理解为地址。也是在new了一个对象后,该对象是存在JVM的Heap区,也就是堆。那么必然有一个地址要指向这个对象的在JVM中的位置,那么,指向这个对象的这个地址就可以简单的理解为“引用”。
那么,上面简单的叙述了一下“传值”和“传引用”这俩个概念。再简单的总结下就是,如果是向方法中传递值,也就是传值,那么实际就是拷贝一份数据,在方法内部进行操作。而传引用则是将一个对象的地址传递至方法内部。
二者到底有什么区别呢?个人理解有如下几个区别:
一、“传值”传递的是一个值,而“传引用”传递的是指向一个另一块内存空间的地址;
二、“传值”实际是将一个值的拷贝传递至方法内部,这个值的原始数据是不会改变的,无论你内部进行的是何种操作,都不会改变这个源数据的值;而“传引用”传递进去的则是指向一个对象的地址,那么在方法内部进行实际操作的时候,就很可能会改变该对象的属性值(当然具体是否改变,还需要结合具体的业务)。
在这里引出另外一个问题,在java中到底是只存在“传值”呢?还是既存在“传值”又存在“传引用”呢?在网上,就分成了两种意见。我认为,这只是一个角度的问题。怎么理解呢?学过汇编的同学都知道,在内存当中,无论是数据,还是代码 其本质都是二进制数据,到底是数据呢?还是代码呢?这只是将这些二进制数据根据其作用分为不同的俩类来加以区分。同样的道理,到底是值呢,还是引用呢?从本质上来讲,引用(这里简单的理解为地址)它说白了也就是一个值。那么认为只有“传值”这一种方式的同学,则是从一个更本质的角度来看待这个问题。那么,认为是两种方式的同学们也是没有问题的。因为的确二者传递至方法内部后,操作的对象是不同的,“传值”是对传进来的值,也就是8种基本数据类型外加String类进行操作,而“传引用”这是对传进来的地址指向的对象进行操作,当然也可以对传进来的“引用”进行操作。

六.创建对象的方式

创建对象的方式,克隆之后的对象和原对象区别
1 使用new操作符创建一个对象
2 使用clone方法复制一个对象
new操作符的本意是分配内存。程序执行到new操作符时, 首先去看new操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间。分配完内存之后,再调用构造函数,填充对象的各个域,这一步叫做对象的初始化,构造方法返回后,一个对象创建完毕,可以把他的引用(地址)发布到外部,在外部就可以使用这个引用操纵这个对象。 而clone在第一步是和new相似的, 都是分配内存,调用clone方法时,分配的内存和源对象(即调用clone方法的对象)相同,然后再使用原对象中对应的各个域,填充新对象的域, 填充完成之后,clone方法返回,一个新的相同的对象被创建,同样可以把这个新对象的引用发布到外部。
对象创建的几种方法:
1.使用new关键字
2.使用clone方法
3.反射机制
4.反序列化
以上四种都可以产生java对象 1,3都会明确的显式的调用构造函数 2是在内存上对已有对象的影印 所以不会调用构造函数 4是从文件中还原类的对象 也不会调用构造函数

七.反射

反射就是获取类的完整信息,比如类的方法,属性等
1)如果出现异常,怎么办,在哪层捕获异常
2)怎样自定义异常?

八. ==和equals的区别

(==和equals的区别)
① = = 比较的是数值,比较对象的时候,比较的是地址值
 ② equals比较的是内容,但是,光内容相等,不是真正的相等,只有hashcode值相等时,才是真正的相等

九.数组集合类

1)ArrayList和数组的区别?ArrayList的变长是怎么实现的?
ArrayList是集合,可以一直追加,数组是定长,不能改变长度
2)ArrayList构造器
① 空构造器,默认容量是10
② 参数为int型的构造器,指定初始容量。
3)ArrayList的底层原理是什么?
底层数据结构是数组可以快速查询但是添加和删除慢,有索引可以避免循环遍历节省时间,继承collection接口
4)Hashmap的底层原理
链表和数组 底层是set

  1. HashMap终极整理从数据结构上看,hashmap是一个“链表散列”,底层实现仍然是一个数组,只不过数组的每一项是一条链,新建一个hashMap,都会初始化一个table数组,数组元素是一个entry节点(Entry是hashmap的内部类,包含了key,value,下一个节点next,以及hash值 ),正是由于Entry才构成了table数组的项为链表。大体介绍:基于哈希表的Map接口实现,以key-value形式存在。在HashMap中,key-value总是会当做一个整体来处理,系统会根据hash算法来来计算key-value的存储位置.系统根据key的hashcode来决定Entry在table数组中的存储位置,在取的过程中同样根据key的hashcode取出相对应的Entry对象。存储实现:put(key,value)首先判断key是否为null,若为null,则直接调用putForNullKey方法(保存null与table第一个位置中,这是HashMap允许为null的原因 )。若不为空则先计算key的hash值,然后根据hash值搜索在table数组中的索引位置(迭代–>为了防止相同的key值,找到key保存的位置),如果table数组在该位置处有元素,则通过比较是否存在相同的key(hash相同),若存在则覆盖原来key的value,否则将该元素保存在链头(最先保存的元素放在链尾)。若table在该处没有元素,则直接保存。addEntry(hash, key, value, i); -->将key,value添加至i位置处。此方法注意链的产生和扩容问题。读取实现(get(key))通过key的hash值找到在table数组中的索引处的Entry,然后返回该key对应的value即可。 注意hashMap底层数组长度是2的N次方,是hashMap在速度上的优化,因为不同hash值发生碰撞的概率比较小,这样使得数据在table数组中分布比较均匀,查询速度也会比较快。
    2)Enumeration接口和iterator接口的区别?
    3)Cocurrenthashmap
    CocurrentHashMap利用锁分段技术增加了锁的数目,从而使争夺同一把锁的线程的数目得到控制。
     锁分段技术就是对数据集进行分段,每段竞争一把锁,不同数据段的数据不 存 在锁竞争,从而有效提高 高并发访问效率。
     CocurrentHashMap在get方法是无需加锁的,因为用到的共享变量都采用volatile关键字修饰,巴证共享变量在线程之间的可见性(每次读取都先同步缓存和内存,直接从内存中获取值,虽然不是原子操作,但根据JAVA内存模型的happen before原则,对volatile字段的写入操作先于读操作,能够保证不会脏读),volatile为了让变量提供线程之间的内存可见性,会禁止程序执行结果的重排序(导致缓存优化的效果降低)
    4)List、set、map的区别?ArrayList和LinkedList、ArrayList和Vector、HashSet和TreeSet、HashMap与TreeMap和HashTable 区别应用场景?
    list与Set、Map区别及适用场景
    1、List,Set都是继承自Collection接口,Map则不是
    2、List特点:元素有放入顺序,元素可重复 ,Set特点:元素无放入顺序,元素不可重复,重复元素会覆盖掉,(注意:元素虽然无放入顺序,但是元素在set中的位置是有该元素的HashCode决定的,其位置其实是固定的,加入Set 的Object必须定义equals()方法 ,另外list支持for循环,也就是通过下标来遍历,也可以用迭代器,但是set只能用迭代,因为他无序,无法用下标来取得想要的值。)
    3.Set和List对比:
    Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。
    List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变。
    4.Map适合储存键值对的数据
    5.线程安全集合类与非线程安全集合类
    LinkedList、ArrayList、HashSet是非线程安全的,Vector是线程安全的;
    HashMap是非线程安全的,HashTable是线程安全的;
    StringBuilder是非线程安全的,StringBuffer是线程安全的。
    ArrayList与LinkedList的区别和适用场景
    Arraylist:
    优点:ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高(在内存里是连着放的)。
    缺点:因为地址连续, ArrayList要移动数据,所以插入和删除操作效率比较低。
    LinkedList:
    优点:LinkedList基于链表的数据结构,地址是任意的,所以在开辟内存空间的时候不需要等一个连续的地址,对于新增和删除操作add和remove,LinedList比较占优势。LinkedList 适用于要头尾操作或插入指定位置的场景
    缺点:因为LinkedList要移动指针,所以查询操作性能比较低。
    适用场景分析:
    当需要对数据进行对此访问的情况下选用ArrayList,当需要对数据进行多次增加删除修改时采用LinkedList。
    ArrayList与Vector的区别和适用场景
    ArrayList有三个构造方法:
    Java代码
    1.public ArrayList(int initialCapacity)//构造一个具有指定初始容量的空列表。
    2.public ArrayList()//构造一个初始容量为10的空列表。
    3.public ArrayList(Collection<? extends E> c)//构造一个包含指定 collection 的元素的列表
    Vector有四个构造方法:
    Java代码
    1.public Vector()//使用指定的初始容量和等于零的容量增量构造一个空向量。
    2.public Vector(int initialCapacity)//构造一个空向量,使其内部数据数组的大小,其标准容量增量为零。
    3.public Vector(Collection<? extends E> c)//构造一个包含指定 collection 中的元素的向量
    4.public Vector(int initialCapacity,int capacityIncrement)//使用指定的初始容量和容量增量构造一个空的向量
    ArrayList和Vector都是用数组实现的,主要有这么三个区别:
    1.Vector是多线程安全的,线程安全就是说多线程访问同一代码,不会产生不确定的结果。而ArrayList不是,这个可以从源码中看出,Vector类中的方法很多有synchronized进行修饰,这样就导致了Vector在效率上无法与ArrayList相比;
    2.两个都是采用的线性连续空间存储元素,但是当空间不足的时候,两个类的增加方式是不同。
    3.Vector可以设置增长因子,而ArrayList不可以。
    4.Vector是一种老的动态数组,是线程同步的,效率很低,一般不赞成使用。
    适用场景分析:
    1.Vector是线程同步的,所以它也是线程安全的,而ArrayList是线程异步的,是不安全的。如果不考虑到线程的安全因素,一般用ArrayList效率比较高。
    2.如果集合中的元素的数目大于目前集合数组的长度时,在集合中使用数据量比较大的数据,用Vector有一定的优势。
    HashSet与Treeset的适用场景
    1.TreeSet 是二差树(红黑树的树据结构)实现的,Treeset中的数据是自动排好序的,不允许放入null值
    2.HashSet 是哈希表实现的,HashSet中的数据是无序的,可以放入null,但只能放入一个null,两者中的值都不能重复,就如数据库中唯一约束
    3.HashSet要求放入的对象必须实现HashCode()方法,放入的对象,是以hashcode码作为标识的,而具有相同内容的String对象,hashcode是一样,所以放入的内容不能重复。但是同一个类的对象可以放入不同的实例
    适用场景分析:HashSet是基于Hash算法实现的,其性能通常都优于TreeSet。为快速查找而设计的Set,我们通常都应该使用HashSet,在我们需要排序的功能时,我们才使用TreeSet。
    HashMap与TreeMap、HashTable的区别及适用场景
    HashMap 非线程安全
    HashMap:基于哈希表实现。使用HashMap要求添加的键类明确定义了hashCode()和equals()[可以重写hashCode()和equals()],为了优化HashMap空间的使用,您可以调优初始容量和负载因子。
    TreeMap:非线程安全基于红黑树实现。TreeMap没有调优选项,因为该树总处于平衡状态。
    适用场景分析:
    HashMap和HashTable:HashMap去掉了HashTable的contains方法,但是加上了containsValue()和containsKey()方法。HashTable同步的,而HashMap是非同步的,效率上比HashTable要高。HashMap允许空键值,而HashTable不允许。
    HashMap:适用于Map中插入、删除和定位元素。
    Treemap:适用于按自然顺序或自定义顺序遍历键(key)。
    8)平时使用那些集合?(map,list)其接口是什么?还有那些接口?collect下有哪些接口?谈谈你对list的理解?有什么特性?list里面分为几种,都有哪些?谈谈arraylist 和 linkedlist底层都怎么实现的?有什么异同?谈谈set?(特性),简单谈谈对map的理解?hashmap,list从使用上来说不同的点有哪些?map以什么形式存储?是一个一个存还是通过什么算法?

十.String类问题

1)String在内存中的位置
常量池和堆
2)String能否作用在switch上?
类似题目:
3)String,stringbuffer,stringbuilder之间的区别?
首先分两类: string 不可追加 stringbuffer,stringbuilder可追加
然后:stringbuffer线程安全,stringbuilder线程不安全
StringBufer、StringBuilder和 String一样,也用来代表字符串。String被称为不可变字符串,底层是使用 final修饰的字节数组是不可变的,任何对 String的改变都会引发新的 String对象的生成;StringBuffer则是可变类,任何对它所指代的字符串的改变都不会产生新的对象。既然可变和不可变都有了,为何还有一个 StringBuilder呢?相信初期的你,在进行 append时,一般都会选择 StringBufer吧!
HashTable是线程安全的,很多方法都是 synchronized方法,而
HashMap不是线程安全的,但其在单线程程序中的性能比 HashTable要高。StringBufer和StringBuilder类的区别也是如此,他们的原理和操作基本相同,区别在于 StringBuferd支持并发操作,线性安全的,适合多线程中使用。StringBuilder不支持并发操作,线性不安全的,不适合多线程中使用。新引入的 StringBuilder类不是线程安全的,但其在单线程中的性能比StringBufer高。

十一.线程问题

1)线程安全,lock是什么?
什么叫做线程安全,什么叫做线程不安全?
首先明白线程的工作原理。Jvm(虚拟机)有一个 main memory(主存),一个线程对一个 variable(变量)进行操作时,都首先复制到自己的自己的 work memory (工作内存)中,操作完之后再写入 main memory 中。而此时多个线程同时操作变量,就可能出现很多不可预知的结果。
Synchronized 的关键是建立一个监控区,这个监控区你可以放要修改的变量或者一些你想要放进去的方法。通过给这个监控区加锁来实现线程安全。每个线程在获得这个锁之后,要执行完(先加载到工作内存,进行更新使用,完毕加载到主存)这个过程才释放他得到的锁。
怎么实现线程安全?
基本上所有的并发模式在解决线程安全问题上 ,都采用“同步互斥访问”
就是,在同一时刻:只能有一个线程访问同步资源。
两种方式实现:synchornized 和 lock
lock
synchronized 是 java 中的一个关键字,也就是说是 Java 语言内置的特性。那么为什么会出现 Lock 呢?
在上面一篇文章中,我们了解到如果一个代码块被 synchronized 修饰了,当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的线程释放锁,而这里获取锁的线程释放锁只会有两种情况:
1)获取锁的线程执行完了该代码块,然后线程释放对锁的占有;
2)线程执行发生异常,此时 JVM 会让线程自动释放锁。
那么如果这个获取锁的线程由于要等待 IO 或者其他原因(比如调用 sleep 方法)被阻塞了,但是又没有释放锁,其他线程便只能干巴巴地等待,试想一下,这多么影响程序执行效率。
因此就需要有一种机制可以不让等待的线程一直无期限地等待下去(比如只等待一定的时间或者能够响应中断),通过 Lock 就可以办到。
另外,通过 Lock 可以知道线程有没有成功获取到锁。这个是 synchronized 无法办到的。
总结一下,也就是说 Lock 提供了比 synchronized 更多的功能。但是要注意以下几点:
1)Lock 不是 Java 语言内置的,synchronized 是 Java 语言的关键字,因此是内置特性。Lock 是一个类,通过这个类可以实现同步访问;
2)Lock 和 synchronized 有一点非常大的不同,采用 synchronized 不需要用户去手动释放锁,当 synchronized 方法或者 synchronized 代码块执行完之后,系统会自动让线程释放对锁的占用;而 Lock 则必须要用户去手动释放
锁,如果没有主动释放锁,就有可能导致出现死锁现象。
2)实现并启动多线程的方法?
有两种
一种是一类,继承 thread 类,重写 run 方法。用 start 方法启动线程
另一种是一个类,实现 runnable 接口,实现 run 方法,用 new
Thread(Runnable target).start()方法来启动
3)Run()和start()的区别?
Run()是完成一个操作,方法 run()称为线程体
Start()方法是来启动一个线程
4)多线程之间的通信方式?
同步,while轮询,wait/notify,管道通信
5)怎样实现多线程?你喜欢那种方式?
1、继承Thread类创建线程
Thread类本质上是实现了Runnable接口的一个实例,代表一个线程的实例。启动线程的唯一方法就是通过Thread类的start()实例方法。start()方法是一个native方法,它将启动一个新线程,并执行run()方法。这种方式实现多线程很简单,通过自己的类直接extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。
2、实现Runnable接口创建线程
如果自己的类已经extends另一个类,就无法直接extends Thread,此时,可以实现一个Runnable接口,
3、实现Callable接口通过FutureTask包装器来创建Thread线程
4、使用ExecutorService、Callable、Future实现有返回结果的线程
具体代码可参考:https://www.cnblogs.com/felixzh/p/6036074.html

6)多线程中,生产者消费者模式的实现方式
方法一: wait() 和 notify() 通信方法实现
方法二:采用阻塞队列实现生产者消费者模式
7)多线程的原理
相当于玩游戏机,只有一个游戏机(cpu),可是有很多人
要玩,于是,start 是排队!等 CPU 选中你就是轮到你,你就 run(),当
CPU 的运行的时间片执行完,这个线程就继续排队,等待下一次的 run
()。
调用 start()后,线程会被放到等待队列,等待 CPU 调度,并不一定要
马上开始执行,只是将这个线程置于可动行状态。然后通过 JVM,线程
Thread 会调用 run()方法,执行本线程的线程体。先调用 start 后调用
run,这么麻烦,为了不直接调用 run?就是为了实现多线程的优点,没
这个 start 不行。
1.start()方法来启动线程,真正实现了多线程运行。这时无需等待 run
方法体代码执行完毕,可以直接继续执行下面的代码;通过调用 Thread
类的 start()方法来启动一个线程, 这时此线程是处于就绪状态, 并没有
运行。 然后通过此 Thread 类调用方法 run()来完成其运行操作的, 这里
方法 run()称为线程体,它包含了要执行的这个线程的内容, Run 方法运
行结束, 此线程终止。然后 CPU 再调度其它线程。
2.run()方法当作普通方法的方式调用。程序还是要顺序执行,要等待
run 方法体执行完毕后,才可继续执行下面的代码; 程序中只有主线程—
—这一个线程, 其程序执行路径还是只有一条, 这样就没有达到写线程
的目的。

十二.数据结构方面

1)二叉树的原理
二叉树的定义:
二叉树是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树的形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。
二叉树(BinaryTree)是n(n≥0)个结点的有限集,它或者是空集(n=0),或者由一个根结点及两棵互不相交的、分别称作这个根的左子树和右子树的二叉树组成。
这个定义是递归的。由于左、右子树也是二叉树, 因此子树也可为空树。下图中展现了五种不同基本形态的二叉树。
其中 (a) 为空树, (b) 为仅有一个结点的二叉树, © 是仅有左子树而右子树为空的二叉树, (d) 是仅有右子树而左子树为空的二叉树, (e) 是左、右子树均非空的二叉树。这里应特别注意的是,二叉树的左子树和右子树是严格区分并且不能随意颠倒的,图 © 与图 (d) 就是两棵不同的二叉树。

十三.TCP三次握手

1、阻塞队列问题
当队列是空时,从队列中获取元素的操作将被阻塞,当队列是满时,往队列里添加元素的操作将被阻塞。

十四.io流

1)IO流的分类:
通常根据流数据格式来分:
字节流:处理声音或者图片等二进制的数据的流,比如 InputStream
字符流:处理文本数据比如(txt 文件)的流,比如 InputStreamreader
根据数据的流向来分:输入流:读数据
输出流:写数据

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值