卷妹带你回顾Java基础(一)每日更新Day11
👩💻博客主页:京与旧铺的博客主页
✨欢迎关注🖱点赞🎀收藏⭐留言✒
🔮本文由京与旧铺原创,csdn首发!
😘系列专栏:java学习
👕参考网站:牛客网
💻首发时间:🎞2022年8月17日🎠
🎨你做三四月的事,八九月就会有答案,一起加油吧
🀄如果觉得博主的文章还不错的话,请三连支持一下博主哦
🎧最后的话,作者是一个新人,在很多方面还做的不好,欢迎大佬指正,一起学习哦,冲冲冲
💬推荐一款模拟面试、刷题神器👉
🛒导航小助手🎪
break ,continue ,return 的区别及作用
break 跳出总上一层循环,不再执行循环(结束当前的循环体)continue 跳出本次循环,继续执行下次循
环(结束正在执行的循环 进入下一个循环条件)
return 程序返回,不再执行下面的代码(结束当前的方法 直接返回)
面向对象的特征有哪些方面
面向对象的特征主要有以下几个方面:
抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行 为抽象两方面。抽象只
关注对象有哪些属性和行为,并不关注这些行为的细节是 什么。
封装 : 封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如 果属性不想
被外界访问,我们大可不必提供方法给外界访问。但是如果一个类没 有提供给外界访问的方法,那
么这个类也没有什么意义了。
继承 : 继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新 的数据或新
的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用 继承我们能够非常方便地复用
以前的代码。
关于继承如下 3 点请记住:
1.子类拥有父类非 private 的属性和方法。
2.子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
3.子类可以用自己的方式实现父类的方法。
多态 : 所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出 的方法调用
在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到 底会指向哪个类的实例对象,
该引用变量发出的方法调用到底是哪个类中实现的 方法,必须在由程序运行期间才能决定。
在Java中有两种形式可以实现多态:继承(多个子类对同一方法的重写)和接口 (实现接口并覆盖
接口中同一方法)。
其中Java 面向对象编程三大特性:封装 继承 多态
封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式,将变化隔离,便 于使用,提高复用性和
安全性。
继承:继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以 增加新的数据或新的功
能,也可以用父类的功能,但不能选择性地继承父类。通 过使用继承可以提高代码复用性。继承是多态
的前提。
关于继承如下 3 点请记住:
\1. 子类拥有父类非 private 的属性和方法。
\2. 子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
\3. 子类可以用自己的方式实现父类的方法。
多态性:父类或接口定义的引用变量可以指向子类或具体实现类的实例对象。提 高了程序的拓展性。
在Java中有两种形式可以实现多态:继承(多个子类对同一方法的重写)和接口 (实现接口并覆盖接口
中同一方法)。
方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重 写(override)实现的是
运行时的多态性(也称为后绑定)。一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是 哪个类中实现的方法,
必须在由程序运行期间才能决定。运行时的多态是面向对 象精髓的东西,要实现多态需要做两件事:
方法重写(子类继承父类并重写父类中已有的或抽象的方法);
对象造型(用父类型引用子类型对象,这样同样的引用调用同样的方法就会根据 子类对象的不同而
表现出不同的行为)。
什么是多态机制?**Java语言是如何实现多态的?**
所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出 的方法调用在编程时并
不确定,而是在程序运行期间才确定,即一个引用变量倒 底会指向哪个类的实例对象,该引用变量发出
的方法调用到底是哪个类中实现的 方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具
体的类,这 样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而 导致该引用
调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时 所绑定的具体代码,让程序可以选
择多个运行状态,这就是多态性。 多态分为编译时多态和运行时多态。其中编辑时多态是静态的,主要
是指方法的 重载,它是根据参数列表的不同来区分不同的函数,通过编辑之后会变成两个不 同的函数,
在运行时谈不上多态。而运行时多态是动态的,它是通过动态绑定来 实现的,也就是我们所说的多态性
多态的实现
Java实现多态有三个必要条件:继承、重写、向上转型。
继承:在多态中必须存在有继承关系的子类和父类。
重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的 方法。
向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具 备技能调用父类的方法
和子类的方法。
只有满足了上述三个条件,我们才能够在同一个继承结构中使用统一的逻辑实现 代码处理不同的对象,
从而达到执行不同的行为。
对于Java而言,它多态的实现机制遵循一个原则:当超类对象引用变量引用子类 对象时,被引用对象的
类型而不是引用变量的类型决定了调用谁的成员方法,但 是这个被调用的方法必须是在超类中定义过
的,也就是说被子类覆盖的方法。
抽象类和接口的对比
抽象类是用来捕捉子类的通用特性的。接口是抽象方法的集合。
从设计层面来说,抽象类是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范。
相同点
接口和抽象类都不能实例化
都位于继承的顶端,用于被其他实现或继承
都包含抽象方法,其子类都必须覆写这些抽象方法
不同点
备注:Java8中接口中引入默认方法和静态方法,以此来减少抽象类和接口之间 的差异。
现在,我们可以为接口提供默认实现的方法了,并且不用强制子类来实现它。 接口和抽象类各有优缺
点,在接口和抽象类的选择上,必须遵守这样一个原则:
行为模型应该总是通过接口而不是抽象类定义,所以通常是优先选用接口,尽量 少用抽象类。
选择抽象类的时候通常是如下情况:需要定义子类的行为,又要为子类提供通用 的功能。
抽象类能使用 final 修饰吗?
不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承, 这样彼此就会产生矛
盾,所以 final 不能修饰抽象类
成员变量与局部变量的区别有哪些
变量:在程序执行的过程中,在某个范围内其值可以发生改变的量。从本质上 讲,变量其实是内存中的
一小块区域 成员变量:方法外部,类内部定义的变量 局部变量:类的方法中的变量。 成员变量和局部
变量的区别
作用域
成员变量:针对整个类有效。
局部变量:只在某个范围内有效。(一般指的就是方法,语句体内)
构造方法有哪些特性?
名字与类名相同;
没有返回值,但不能用void声明构造函数;
生成类的对象时自动执行,无需调用。
静态变量和实例变量区别
静态变量: 静态变量由于不属于任何实例对象,属于类的,所以在内存中只会 有一份,在类的加载过程
中,JVM只为静态变量分配一次内存空间。
实例变量: 每次创建对象,都会为每个对象分配成员变量内存空间,实例变量 是属于实例对象的,在内
存中,创建几次对象,就有几份成员变量。
静态变量与普通变量区别
static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有 的对象所共享,在内存
中只有一个副本,它当且仅当在类初次加载时会被初始 化。而非静态变量是对象所拥有的,在创建对象
的时候被初始化,存在多个副 本,各个对象拥有的副本互不影响。
还有一点就是static成员变量的初始化顺序按照定义的顺序进行初始化。
静态方法和实例方法有何不同?
静态方法和实例方法的区别主要体现在两个方面:
\1. 在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使 用"对象名.方法名"的方式。而
实例方法只有后面这种方式。也就是说,调 用静态方法可以无需创建对象。
\2. 静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量 和静态方法),而不允许访
问实例成员变量和实例方法;实例方法则无此 限制
重载(**Overload)和重写(Override)的区别。重载的方法能 否根**
据返回类型进行区分?
方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态 性,而后者实现的是运行
时的多态性。
重载:发生在同一个类中,方法名相同参数列表不同(参数类型不同、个数不 同、顺序不同),与方法
返回值和访问修饰符无关,即重载的方法不能根据返回 类型进行区分
重写:发生在父子类中,方法名、参数列表必须相同,返回值小于等于父类,抛 出的异常小于等于父
类,访问修饰符大于等于父类(里氏代换原则);如果父类 方法访问修饰符为private则子类中就不是重
写。
值传递和引用传递有什么区别
值传递:指的是在方法调用时,传递的参数是按值的拷贝传递,传递的是值的拷 贝,也就是说传递后就
互不相关了。 引用传递:指的是在方法调用时,传递的参数是按引用进行传递,其实传递的引 用的地
址,也就是变量所对应的内存空间的地址。传递的是值的引用,也就是说 传递前和传递后都指向同一个
引用(也就是同一个内存空间)。
JDK 中常用的包有哪些
java.lang:这个是系统的基础类;
java.io:这里面是所有输入输出有关的类,比如文件操作等;
java.nio:为了完善 io 包中的功能,提高 io 包中性能而写的一个新包;
java.net:这里面是与网络有关的类;
java.util:这个是系统辅助类,特别是集合类;
java.sql:这个是数据库操作的类。
java 中 IO 流分为几种**?**
按照流的流向分,可以分为输入流和输出流; 按照操作单元划分,可以划分为字节流和字符流; 按照流
的角色划分为节点流和处理流。 Java Io流共涉及40多个类,这些类看上去很杂乱,但实际上很有规则,
而且彼 此之间存在非常紧密的联系, Java I0流的40多个类都是从如下4个抽象类基类 中派生出来的。
InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符 输入流。
OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输 出流
BIO,NIO,AIO 有什么区别**?**
简答
BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并
发处理能力低。
NIO:Non IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过
Channel(通道)通讯,实现了多路复用。
AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO
,异步 IO 的操作基于事件和回调机制。
详细回答
BIO (Blocking I/O): 同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。在活动
连接数不是特别高(小于单机1000)的情况下,这种模型是比较不错的,可以让每一个连接专注于
自己的 I/O 并且编程模型简单,也不用过多考虑系统的过载、限流等问题。线程池本身就是一个天
然的漏斗,可以缓冲一些系统处理不了的连接或请求。但是,当面对十万甚至百万级连接的时候,
传统的 BIO 模型是无能为力的。因此,我们需要一种更高效的 I/O 处理模型来应对更高的并发量。
NIO (New I/O): NIO是一种同步非阻塞的I/O模型,在Java 1.4 中引入了NIO框架,对应 java.nio
包,提供了 Channel , Selector,Buffer等抽象。NIO中的 N可以理解为Non-blocking,不单纯是
New。它支持面向缓冲的,基于通道的I/O操作方法。 NIO提供了与传统BIO模型中的 Socket 和
ServerSocket 相对应的 SocketChannel 和 ServerSocketChannel 两种不同的套接字通道实现,两
种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能
和可靠性都不好;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可以使用同步阻塞
I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞
模式来开发
AIO (Asynchronous I/O): AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非
阻塞的IO模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵
塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。AIO 是异步IO的缩写,
虽然 NIO 在网络操作中,提供了非阻塞的方法,但是 NIO 的 IO 行为还是同步的。对于 NIO 来
说,我们的业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程自行进行 IO 操作,IO操作本身是同步的。查阅网上相关资料,我发现就目前来说 AIO 的应用还不是很广泛,Netty 之前也
尝试使用过 AIO,不过又放弃了。
Files**的常用方法都有哪些?**
Files. exists():检测文件路径是否存在。
Files. createFile():创建文件。
Files. createDirectory():创建文件夹。
Files. delete():删除一个文件或目录。
Files. copy():复制文件。
Files. move():移动文件。
Files. size():查看文件个数。
Files. read():读取文件。
Files. write():写入文件。
什么是反射机制?
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个
对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为
java语言的反射机制。
静态编译和动态编译
静态编译:在编译时确定类型,绑定对象
动态编译:运行时确定类型,绑定对象
反射机制优缺点
优点: 运行期类型的判断,动态加载类,提高代码灵活度。
缺点: 性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能
比直接的java代码要慢很多。
Java**获取反射的三种方法**
1.通过new对象实现反射机制
2.通过路径实现反射机制
3.通过类名实现反射机制
什么是字符串常量池?
字符串常量池位于堆内存中,专门用来存储字符串常量,可以提高内存的使用率,避免开辟多块空间存
储相同的字符串,在创建字符串时 JVM 会首先检查字符串常量池,如果该字符串已经存在池中,则返回
它的引用,如果不存在,则实例化一个字符串放到池中,并返回其引用。
String**有哪些特性**
不变性:String 是只读字符串,是一个典型的 immutable 对象,对它进行任何操作,其实都是创
建一个新的对象,再把引用指向该对象。不变模式的主要作用在于当一个对象需要被多线程共享并
频繁访问时,可以保证数据的一致性。
常量池优化:String 对象创建之后,会在字符串常量池中进行缓存,如果下次创建同样的对象时,
会直接返回缓存的引用。
final:使用 final 来定义 String 类,表示 String 类不能被继承,提高了系统的安全性。
String**和StringBuffer、StringBuilder的区别是什么?String** 为什么是不可变的
可变性
String类中使用字符数组保存字符串,private final char value[],所以 string对象是不可变的。
StringBuilder与StringBuffer都继承自
1 String str1 = "hello"; //str1指向静态区
2 String str2 = new String("hello"); //str2指向堆上的对象
3 String str3 = "hello";
4 String str4 = new String("hello");
5 System.out.println(str1.equals(str2)); //true
6 System.out.println(str2.equals(str4)); //true
7 System.out.println(str1 == str3); //true
8 System.out.println(str1 == str2); //false
9 System.out.println(str2 == str4); //false
10 System.out.println(str2 == "hello"); //false
11 str2 = str1;
12 System.out.println(str2 == "hello"); //true
1 // StringBuffer reverse
2 StringBuffer stringBuffer = new StringBuffer();
3 stringBuffer. append("abcdefg");
4 System. out. println(stringBuffer. reverse()); // gfedcba
5 // StringBuilder reverse
6 StringBuilder stringBuilder = new StringBuilder();
7 stringBuilder. append("abcdefg");
8 System. out. println(stringBuilder. reverse()); // gfedcbaAbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,char[] value,这
两种对象都是可变的。线程安全性
String中的对象是不可变的,也就可以理解为常量,线程安全。
AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如
expandCapacity、append、insert、indexOf等公共方法。StringBuffer对方法加了同步锁或者对调用
的方法加了同步锁,所以是线程安全的。StringBuilder并没有对方法进行加同步锁,所以是非线程安全
的。
性能
每次对String 类型进行改变的时候,都会生成一个新的String对象,然后将指针指向新的String 对象。
StringBuffer每次都会对StringBuffer对象本身进行操
作,而不是生成新的对象并改变对象引用。相同情况下使用StirngBuilder 相比使用StringBuffer 仅能获
得10%~15% 左右的性能提升,但却要冒多线程不安全的风险。
对于三者使用的总结
如果要操作少量的数据用 = String 单线程操作字符串缓冲区 下操作大量数据 = StringBuilder 多线程操
作字符串缓冲区 下操作大量数据 = StringBuffer
int 和 Integer 有什么区别
Java 是一个近乎纯洁的面向对象编程语言,但是为了编程的方便还是引入了基本数据类型,但是为了能
够将这些基本数据类型当成对象操作,Java 为每一个基本数据类型都引入了对应的包装类型(wrapper
class),int 的包装类就是 Integer,从 Java 5 开始引入了自动装箱/拆箱机制,使得二者可以相互转
换。
Java 为每个原始类型提供了包装类型:
原始类型: boolean,char,byte,short,int,long,float,double 包装类型:Boolean,
Character,Byte,Short,Integer,Long,Float,
Double
Integer a= 127 与 Integer b = 127**相等吗**
对于对象引用类型:==比较的是对象的内存地址。
对于基本数据类型:==比较的是值。如果整型字面量的值在-128到127之间,那么自动装箱时不会new
新的Integer 对象,而是直接引用常量池中的Integer对象,超过范围 a1==b1的结果是false
常用的集合类有哪些?
Map接口和Collection接口是所有集合框架的父接口:
\1. Collection接口的子接口包括:Set接口和List接口
\2. Map接口的实现类主要有:HashMap、TreeMap、Hashtable、 ConcurrentHashMap以及
Properties等
\3. Set接口的实现类主要有:HashSet、TreeSet、LinkedHashSet等
\4. List接口的实现类主要有:ArrayList、LinkedList、Stack以及Vector等
集合框架底层数据结构
Collection
List
Arraylist: Object数组
Vector: Object数组
LinkedList: 双向循环链表
Set
HashSet(无序,唯一):基于 HashMap 实现的,底层采用 HashMap 来保存元素
LinkedHashSet: LinkedHashSet 继承与 HashSet,并且其内部是通过 LinkedHashMap 来实现
的。有点类似于我们之前说的LinkedHashMap 其内部是基 于 Hashmap 实现一样,不过还是有一
点点区别的。
TreeSet(有序,唯一): 红黑树(自平衡的排序二叉树。) Map
HashMap: JDK1.8之前HashMap由数组+链表组成的,数组是HashMap的主 体,链表则是主要
为了解决哈希冲突而存在的(
“拉链法”解决冲突).JDK1.8以后
在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转 化为红黑树,
以减少搜索时间
LinkedHashMap:LinkedHashMap 继承自 HashMap,所以它的底层仍然是 基于拉链式散列结
构即由数组和链表或红黑树组成。另外,LinkedHashMap 在上面 结构的基础上,增加了一条双向
链表,使得上面的结构可以保持键值对的插入顺序。 同时通过对链表进行相应的操作,实现了访问
顺序相关逻辑。
HashTable: 数组+链表组成的,数组是 HashMap 的主体,链表则是主要为 了解决哈希冲突而存
在的
TreeMap: 红黑树(自平衡的排序二叉树)
哪些集合类是线程安全的?
vector:就比arraylist多了个同步化机制(线程安全),因为效率较低,现在已 经不太建议使用。
在web应用中,特别是前台页面,往往效率(页面响应速度)是优 先考虑的。
statck:堆栈类,先进后出。
hashtable:就比hashmap多了个线程安全。
enumeration:枚举,相当于迭代器
迭代器 Iterator 是什么?
Iterator 接口提供遍历任何 Collection 的接口。我们可以从一个 Collection 中使用迭代器方法来获取迭
代器实例。迭代器取代了 Java 集合框架中的 Enumeration,迭代器允许调用者在迭代过程中移除元
素。
Iterator 和 ListIterator 有什么区别?
Iterator 可以遍历 Set 和 List 集合,而 ListIterator 只能遍历 List。
Iterator 只能单向遍历,而 ListIterator 可以双向遍历(向前/后遍历)。
ListIterator 实现 Iterator 接口,然后添加了一些额外的功能,比如添加一个元 素、替换一个元
素、获取前面或后面元素的索引位置。
遍历一个 List 有哪些不同的方式?每种方法的实现原理是什 么?**Java** 中 List 遍历
的最佳实践是什么?
遍历方式有以下几种:
\1. for 循环遍历,基于计数器。在集合外部维护一个计数器,然后依次读 取每一个位置的元素,当读
取到后一个元素后停止。
\2. 迭代器遍历,Iterator。Iterator 是面向对象的一个设计模式,目的是屏 蔽不同数据集合的特点,
统一遍历集合的接口。Java 在 Collections 中支 持了 Iterator 模式。
\3. foreach 循环遍历。foreach 内部也是采用了 Iterator 的方式实现,使 用时不需要显式声明
Iterator 或计数器。优点是代码简洁,不易出错;缺 点是只能做简单的遍历,不能在遍历过程中操
作数据集合,例如删除、替 换。
最佳实践:Java Collections 框架中提供了一个 RandomAccess 接口,用来标 记 List 实现是否支持
Random Access。
如果一个数据集合实现了该接口,就意味着它支持 Random Access,按位置读 取元素的平均时间
复杂度为 O(1),如ArrayList。
如果没有实现该接口,表示不支持 Random Access,如LinkedList。 推荐的做法就是,支持
Random Access 的列表可用 for 循环遍历,否则建议 用 Iterator 或 foreach 遍历。
说一下 ArrayList 的优缺点
ArrayList的优点如下:
ArrayList 底层以数组实现,是一种随机访问模式。ArrayList 实现了 RandomAccess 接口,因此查
找的时候非常快。
ArrayList 在顺序添加一个元素的时候非常方便。
ArrayList 的缺点如下:
删除元素的时候,需要做一次元素复制操作。如果要复制的元素很多,那么就会比较耗费性能。
插入元素的时候,也需要做一次元素复制操作,缺点同上。
ArrayList 比较适合顺序添加、随机访问的场景。
如何实现数组和 List 之间的转换?
数组转 List:使用 Arrays. asList(array) 进行转换。
List 转数组:使用 List 自带的 toArray() 方法
ArrayList 和 LinkedList 的区别是什么?
数据结构实现:ArrayList 是动态数组的数据结构实现,而 LinkedList 是双向链表的数据结构实
现。
随机访问效率:ArrayList 比 LinkedList 在随机访问的时候效率要高,因为 LinkedList 是线性的数
据存储方式,所以需要移动指针从前往后依次查找。
增加和删除效率:在非首尾的增加和删除操作,LinkedList 要比 ArrayList 效率要高,因为
ArrayList 增删操作要影响数组内的其他数据的下标。
内存空间占用:LinkedList 比 ArrayList 更占内存,因为 LinkedList 的节点除了存储数据,还存储
了两个引用,一个指向前一个元素,一个指向后一个元素。
线程安全:ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全;
综合来说,在需要频繁读取集合中的元素时,更推荐使用 ArrayList,而在插入和删除操作较多时,更推
荐使用 LinkedList。
补充:数据结构基础之双向链表
双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前
- 点赞
- 收藏
- 关注作者
评论(0)