目录
Java和C语言有什么区别?Java好在哪里?
- 设计思路不一样,
C语言是面向过程的语言,执行效率高,java是面向对象的语言,执行效率比C语言低。
- 通用性不同:
C语言不能跨平台,java可以跨平台直接移植,只要有安装java虚拟机(jvm)就可以了。
语法不同:
- 基本数据类型不同
C语言是 int short long char float double 还有一些特殊类型结构体,指针,联合体等,数组,字符串。
java是 int short long float byte double char boolean ,C语言的基本类型的位数和操作系统和机器相关,而java是固定的。
- 文件组织方式不一样,C语言会把全局变量和方法的声明,放在一个文件里面,叫做头文件,而java是以类来组织文件的。
应用领域不同:
C语言主要用于驱动开发,操作系统,内核开发,嵌入式(单机片),交换机,路由器等网络设备的开发;
java主要是企业应用开发,包括服务器端开发,嵌入式领域,大数据技术,网站领域等。
怎么理解Java的跨平台性,一次编译到处运行?
什么是编译:
编译就是使用编译器把高级语言变成计算机可以识别的二进制语言;
java是一种特殊的高级语言,java程序的执行过程必须经过先编译,后解释两个步骤,首先java源文件被以为字节码文件,然后由jvm解释执行。java编译产生的不是针对特定平台的机器码,而是一种与平台无关的字节码文件(.class文件)。相同的字节码在不同平台上直接运行原本是不可能的,但通过中间的转化器就可以实现了一次编译,到处运行的效果,jvm就是这个转换器,不同平台上的jvm是不同的,但提供给java字节码程序的接口是完全相同的,所以这些字节码不面向任何平台,只面向jvm。
面向对象和面向过程的区别?
面向对象(OOP)是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为。
面向过程就是分析出问题的所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。
如何理解面向对象三大特性:封装、继承、多态?
类的抽象与封装
类的抽象是将类的实现和使用分离,而类的封装是将实现的细节封装起来并且对用户隐藏,用户只需会用就行。
访问权限修饰符的作用域范围从大到小:public --> proetected --> default --> private
import和package关键字的区别
package表明当前类属于那个包空间,永远放在第一行。import是用于导入其他包的类。
封装:(encapsulation)
封装的本质就是通过定义类,并且给类的属性和方法加上访问权限,用于控制在程序中属性的修改的访问级别。简单来说,通过访问权限控制,隐藏重要数据,避免随便修改数据,只对外暴露不会影响类的数据安全的公共方法。
继承(extends)
从已存在的类中定义新的类,实现代码复用,这称为继承。继承在软件重用方面是一个重要且功能强大的特征。
使用场景:
类与对象的关系:一个类具有同一类型的对象的属性和行为.
类于类的关系:有的时候,不同类之间也有一些共同的特征和行为,将这些共同特征和行为提取出来,统一放在一个类中,作为一个通用类。这时可以定义特定的类继承该通用类,这些特定的类继承通用类的可访问数据域和方法。
语法:
使用extends关键字。实例:pulbic subClass extends Student{}
使用继承的注意点
- 父类的私有数据和方法无法被继承,因为private修饰的变量和方法仅限于类的内部。但我们可以通过父类提供的公共访问器/修改器来进行访问和修改(get,set);
- 和传统的理解不同,子类并不是父类的子集。实际上,一个子类通常比父类包含更多的数据和方法。子类是对父类的扩展,父类仅提供数据域和方法。
- 继承表示"是一种"(is-a)(什么是什么)关系,即一个父类与他的子类必须存在 是一种 关系。例如老虎是动物等。
- java只支持单继承,即一个类只能继承一个父类。然而,要实现多重继承可以通过接口来完成。
super关键字与构造方法链
super关键字指代父类,可用于调用父类中的普通方法好构造方法。而this则是对象调用对象的引用。
方法重写
- 子类从父类中继承方法,但有时候,需要根据子类的需求来修改父类的方法实现,这称之为方法重写。
- 注意点:
- 静态方法可以被继承,但不能被重写。因为静态方法输入类本身,若子类定义了同名的静态方法,则与父类的静态方法毫无关联。要调用父类同名静态方法,父类名.静态方法。
- 只有实例方法时可访问(即非私有)。他才能被子类进行方法重写。
- 方法重写是多态实现的重要手段,可以说继承就是为了多态而准备的,继承就是多态实现的前提。
多态(Ploymorphism)
多态就是同一事物的多种不同形态。
实现多态的前提:
- 继承
- 重写
- 父类引用指向子类对象
多态的实现原理--动态绑定:
一个变量必须声明某种类型,变量的类型成为他的声明类型。如果一个引用类型变量,那么他可以是一个null值或者是对该声明类型的引用。但变量的时机类型是引用变量引用的对象的类 。所以调用哪一个方法实际上是由实际类型所决定。这就是动态绑定。
为什么重写equals方法还要重写hashcode方法?
1.使用hashcode方法提前校验,可以避免每一次比对都调用equals方法,提高效率
2.保证是同一个对象,如果重写了equals方法,而没有重写hashcode方法,会出现equals相等的对象,hashcode不相等的情况,重写hashcode方法就是为了避免这种情况的出现。
HashMap原理
hashmap存储数据的时候,是取的key值的哈希值,然后计算数组下标,采用链地址解决冲突,然后进行存储;取数据的时候,依然要先要获取到hash值,找到数组下标,然后for遍历链表集合,进行比较是否有对应的key;
不管是put还是get的时候,都需要得到key的哈希值,去定位key的数组小标;
在get的时候,需要调用equals方法比较是否有相等的key存储过。
“关系操作符生成的是一个boolean结果,它们计算的是操作数的值之间的关系”。
== 比较的是变量存储的地址
为什么要重写equals方法
如果不重写equals方法,使用object的equals方法,他比较是存储的地址,而不是值
我们知道判断的时候先根据hashcode进行的判断,相同的情况下再根据equals()方法进行判断。如果只重写了equals方法,而不重写hashcode的方法,会造成hashcode的值不同,而equals()方法判断出来的结果为true。
.HashCode被设计用来提高性能。
equals()方法与hashCode()方法的区别在于:
如果两个对象相等(equal),那么他们一定有相同的哈希值。 如果两个对象的哈希值相同,但他们未必相等(equal)。
注:== 表示两对象内存地址相同
深克隆和浅克隆
浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原属性所指向的对象的内存地址。
深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
总之深浅克隆都会在堆中新分配一块区域,区别在于对象属性引用的对象是否需要进行克隆(递归性的)。
如图:
pos:当前对象的地址;
son:son属性所指向的地址;
name:对象的name属性。
反射相关
什么是反射:
反射是在程序运行时,能动态查看和修改他的状态;
反射机制是什么:
在运行状态中,对于任意一个类都能够知道这个类的所有属性和方法,对于任意一个对象都能调整他的任意一个方法和属性。
这种动态获取信息以及动态调用对象的方法和功能称为java语言反射机制。
通俗的理解:在运行期间可以对类的内容进行操作。
反射原理:
- 编写的文件源文件.java保存在本地磁盘。
- 编译生成字节码文件.class
- 通过jvm将字节码加载到内存中
- 将字节码加载到内存当中,把整个字节码文件看到一个对象,对象类型为Class类型。
- 获得对象,就可以获得自己吗文件当中所有内容,所有内容包括:构造器,方法,属性。
反射的优缺点:
大幅度提高开发效率,有脸框架可以提高开发效率。
发射的效率比非反射方式的效率低。
反射可以暴露的所有细节,没底线,不安全。
注解的实现原理
1,什么是注解
注解也叫元数据,例如我们常见的@Override和@Deprecated,注解是JDK1.5版本开始引入的一个特性,用于对代码进行说明,可以对包、类、接口、字段、方法参数、局部变量等进行注解
一般常用的注解可以分为三类:
-
一类是Java自带的标准注解,包括@Override(标明重写某个方法)、@Deprecated(标明某个类或方法过时)和@SuppressWarnings(标明要忽略的警告),使用这些注解后编译器就会进行检查。
-
一类为元注解,元注解是用于定义注解的注解,包括@Retention(标明注解被保留的阶段)、@Target(标明注解使用的范围)、@Inherited(标明注解可继承)、@Documented(标明是否生成javadoc文档)
-
一类为自定义注解,可以根据自己的需求定义注解
2. 注解的用途
注解: 是一种分散式的元数据,与源代码紧绑定。
xml: 是一种集中式的元数据,与源代码无绑定。
3. 注解的实现原理
- 注解声明
- 使用注解的元素
- 操作注解使其起作用(注解处理器)
Lambda表达式的优缺点?
优点:
1、代码更加简洁
2、减少匿名内部类的创建,节省资源
3、使用时不用去记忆所使用的接口和抽象函数
缺点:
1、不易于后期维护,必须熟悉lambda表达式和抽象函数中参数的类型
2、可读性差
Stream流式编程
Stream流常用方法
对于Stream流的常用方法,可以分成延迟方法和终结方法
-
延迟方法:返回值类型仍然是 Stream 接口自身类型的方法,支持链式调用(除了终结方法外,其余方法均为延迟方法)
-
终结方法:返回值类型不再是 Stream 接口自身类型的方法,因此不再支持链式调用。常见的终结方法有 count 和forEach 方法
Stream流编程需要注意的点
Stream流属于管道流,只能被消费一次,也就是说第一个Stream流调用方法完毕之后,数据会流到下一个Stream流,并且该流会被关闭,再次使用该流去调用方法将会报错
stream流的好处:
使用stream流式编程不仅可以简化代码开发,增强可读性,还可以在不修改原来集合的基础上对数据进行过滤、映射等操作
设计模式
原文地址:https://www.runoob.com/design-pattern/design-pattern-intro.html
什么是GOF(四人帮,全拼Gang of Four):
在 1994 年,由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 四人合著出版了一本名为 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 的书,该书首次提到了软件开发中设计模式的概念。
四位作者合称 GOF(四人帮,全拼 Gang of Four)。他们所提出的设计模式主要是基于以下的面向对象设计原则。
- 对接口编程而不是对实现编程。
- 优先使用对象组合而不是继承。
设计模式的类型
根据设计模式的参考书 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 中所提到的,公共有23种设计模式,这些模式可以分为三大分类:创建型模式,结构性模式,行为型模式。另一类设计模式:J2EE设计模式。
序号 | 模式 & 描述 | 包括 |
---|---|---|
1 | 创建型模式 这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。 |
|
2 | 结构型模式 这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。 |
|
3 | 行为型模式 这些设计模式特别关注对象之间的通信。 |
|
4 | J2EE 模式 这些设计模式特别关注表示层。这些模式是由 Sun Java Center 鉴定的。 |
|
下面用一个图片来整体描述一下设计模式之间的关系:
设计模式的六大原则
1.开闭原则
开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类。
2.里氏代换原则
里氏代换原则是面向对象设计的基本原则之一。里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现,LSP是继承复用的基石,只有当派生类可以替换掉基类(基类就是父类,派生类就是子类),且软件单位的功能不收到影响时,基类才能真正被复用,而派生类也能够再基类的基础上增加新的行为。里氏替换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象类的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
3.依赖倒转原则
这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。
4.接口隔离原则
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。他还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发,便于升级和维护的软件设计思想,他强调降低依赖,降低耦合。
5.迪米特法则,又称最少知道原则
一个实体当尽量少地与其他实体之间发生相互作用,使得系统功能模快相对独立。
6.合成复用原则
尽量使用合成/聚合的方式,而不是使用继承。
JDK1.8新特性Optional
Optional类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
Optional是个容器:他可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显示进行空值检测。
Optional类的引入很好的解决空指针异常。
类声明:
public final class Optional<T> {}
常用方法:
// 创建一个包装对象值为空的Optional对象
Optional<String> optStr = Optional.empty();
// 创建包装对象值非空的Optional对象
方法: public static <T> Optional<T> of(T value)
Optional<String> optStr1 = Optional.of("optional");
// 创建包装对象值允许为空的Optional对象
方法: public static <T> Optional<T> ofNullable(T value)
Optional<String> optStr2 = Optional.ofNullable(null);
// 如果在这个Optional中包含这个值,返回值,否则抛出异常:NoSuchElementException
方法: public T get()
Optional<Integer> b = Optional.of(value2);
Integer integer = b.get();
// 如果值存在则使用该值执行需用实现的 , 否则不做任何事情。
方法: public void ifPresent(Consumer<? super T> consumer)
Optional<Integer> b = Optional.of(value2);
boolean present = b.isPresent();
//如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的Optional作为map方法返回值,否则返回空Optional。
方法: public<U> Optional<U> map(Function<? super T, ? extends U> mapper)
// 如果getUsername不等于空,就得到里面的值,等于空等于null
Optional.ofNullable(user).map(a -> a.getUsername()).orElse(null)
//如果值存在,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Optional。
方法: public Optional<T> filter(Predicate<? super T> predicate)
注意:orElse方法中的参数类型要和map中类型保持一致
三元运算符
public static int getNum() {
int num1 = 10;
int num2 = 20;
int num3;
// 如果num2小于num1为true时,num3等于30,false时等于0
return num3 = num2 < num1 ? 30 : 0;
}
多线程:
1. 并发:在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行。其中两种并发关系分别是同步和互斥
2. 互斥:进程间相互排斥的使用临界资源的现象,就叫互斥。
3. 同步:进程之间的关系不是相互排斥临界资源的关系,而是相互
依赖的关系。进一步的说明:就是前一个进程的输出作为后一个进程的输入,当第一个进程没有输出时第二个进程必须等待。具有同步关系的一组并发进程相互发送的信息称为消息或事件。
其中并发又有伪并发和真并发,伪并发是指单核处理器的并发,真并发是指多核处理器的并发。
4. 并行:在单处理器中多道程序设计系统中,进程被交替执行,表现出一种并发的外部特种;在多处理器系统中,进程不仅可以交替执行,而且可以重叠执行。在多处理器上的程序才可实现并行处理。从而可知,
并行是针对多处理器而言的。并行是同时发生的多个并发事件,具有并发的含义,但并发不一定并行,也亦是说并发事件之间不一定要同一时刻发生。
5. 多线程:多线程是程序设计的逻辑层概念,它是进程中并发运行的一段代码。多线程可以实现线程间的切换执行。
6. 异步:异步和同步是相对的,同步就是顺序执行,执行完一个再执行下一个,需要等待、协调运行。异步就是彼此独立,在等待某事件的过程中继续做自己的事,不需要等待这一事件完成后再工作。
线程就是实现异步的一个方式。
异步是让调用方法的主线程不需要同步等待另一线程的完成,从而可以让主线程干其它的事情。
异步和多线程并不是一个同等关系,异步是最终目的,多线程只是我们实现异步的一种手段。异步是当一个调用请求发送给被调用者,而调用者不用等待其结果的返回而可以做其它的事情。
实现异步可以采用多线程技术或则交给另外的进程来处理。