java基础5-24

面向对象

java和c语言的区别

  1. 面向对象:Java面向对象;c面向过程。
    (1)面向过程:分析解决问题的步骤,然后用函数把这些步骤一步一步地实现,然后在使用的时候一一调用则可。性能较高,所以单片机、嵌入式开发等一般采用面向过程开发
    (2)面向对象:是把构成问题的事务分解成各个对象,而建立对象的目的也不是为了完成一个个步骤,而是为了描述某个事物在解决整个问题的过程中所发生的行为。面向对象有封装、继承、多态的特性,所以易维护、易复用、易扩展。可以设计出低耦合的系统。 但是性能上来说,比面向过程要低。
  2. 平台无关系:Java只需要一次编译,就可以跨平台使用;c无法跨平台使用。
    原因:JVM。Java编译完成之后,会生成class文件,将生成的文件移到不同的平台时,Java虚拟机会将class文件翻译成计算机所能识别的信息,就可以跨平台使用。
  3. 语法结构上,Java去掉了c里面比较重要的指针的概念
    指针:直接去操作计算机的物理地址,使用c时,需要自己申请内存空间,用完之后还需要手动释放,Java垃圾回收机制解决了这点,不用再去关心申请的内存释放,Java虚拟机会帮助清理一些用不到的空间,从而降低出错可能。
  4. 主要用途不一样,Java主要针对互联网应用开发,c主要偏向于底层开发,所以现在我们所看到的的操作系统,智能设备这些都是使用的c,而我们平时的一些大数据平台,网站开发,比如我们经常使用的电商网站,还有一些企业管理网站等用到的则大都是java。

面向对象三大特征

面向对象的程序设计方法具有三个基本特征:封装、继承、多态。

  1. 封装:将对象的实现细节隐藏起来,然后通过一些公用方法来暴露该对象的功能;
  2. 继承:是面向对象实现软件复用的重要手段,当子类继承父类后,子类可用使用父类的所有功能,并可以拓展功能;
  3. 多态:同一个类型的不同对象在执行同一个方法时,可能表现出多种行为特征。

多态

同一操作用于不同对象,可以产生不同执行结果

实现方式:继承+重写
多态一般分为两种:重写式多态和重载式多态。

重载式多态,也叫编译时多态。
也就是说这种多态在编译时已经确定好了。在调用重载的方法时,通过传入不同的参数最后得到不同的结果。

重写式多态,也叫运行时多态。
通过动态绑定技术来实现,是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。也就是说,只有程序运行起来,你才知道调用的是哪个子类的方法。

  • 通过函数的重写以及向上转型来实现

多态的条件

(1)继承:在多态中必须存在有继承关系的子类和父类。
(2)重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
(3)向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。继承也可以替换为实现接口。

重载重写

重载:一个类中多个同名方法,但是有不同参数个数或参数类型。访问修饰符和返回类型可能不同。
1、重载Overload是一个类中多态性的一种表现
2、重载要求同名方法的参数列表不同(参数类型,参数个数甚至是参数顺序)
3、重载的时候,返回值类型可以相同也可以不相同。无法以返回型别作为重载函数的区分标准

重写:
1、在子类中把父类本身有的方法重新写一遍。
2、在方法名,参数列表,返回类型都相同。
3、访问修饰符的限制大于被重写方法的访问修饰符
(public>protected>default>private)
4、重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常

接口和抽象类

相同点

(1)都不能被实例化
(2)接口的实现类或抽象类的子类都只有实现了接口或抽象类中的方法后才能实例化。

不同点

1)抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法;
2)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;
3)接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;
4)一个类只能继承一个抽象类,而一个类却可以实现多个接口;
5) 实现接口的关键字为implements,继承抽象类的关键字为extends。

Java创建对象有几种方式

1、new创建新对象
2、通过反射机制

(1)使用Java.lang.Class类的newInstance方法调用无参的构造函数创建对象。
User user = User.class.newInstance();
(2)使用java.lang.reflect.Constructor类的newInstance()实例方法。
Constructor constructor = User.class.getConstructor();
User user = constructor.newInstance();

3、采用clone机制

调用一个对象的clone方法,jvm就会创建一个新的对象,将前面对象的内容全部拷贝进去。用clone方法创建对象并不会调用任何构造函数。
要使用clone方法,需要先实现Cloneable接口并实现其定义的clone方法。

4、通过序列化机制

当我们序列化和反序列化一个对象,jvm会给我们创建一个单独的对象。在反序列化时,jvm创建对象并不会调用任何构造函数。
为了反序列化一个对象,我们需要让我们的类实现Serializable接口。

八种数据的基础类型

基本数据类型有8个,可以分为4个小类,分别是整数类型(byte/short/int/long)、浮点类型(float/double)、字符类型(char)、布尔类型(boolean)。

  • 其中,4个整数类型中,int类型最为常用。2个浮点类型中,double最为常用。另外,在这8个基本类型当中,除了布尔类型之外的其他7个类型,都可以看做是数字类型,它们相互之间可以进行类型转换。

String实现的源码和字符串常量池

String实现

String被声明为final,因此不可继承。

  • Java 9之前字符串采用char[]数组来保存字符,即 private final char[] value ;
  • Java 9做了改进,采用byte[]数组来保存字符,即 private final byte[] value ;
    value数组被声明为final,意味着数组初始化之后不能载改变,因此可以保证string不可变。

不可变好处

  1. 可以缓存hash值
    字符串作为基础的数据结构,大量地应用在一些集合容器之中,尤其是一些散列集合,在散列集合中,存放元素都要根据对象的 hashCode() 方法来确定元素的位置。由于字符串 hashcode 属性不会变更,保证了唯一性,使得类似 HashMap,HashSet 等容器才能实现相应的缓存功能。由于String 的不可变,避免重复计算 hashcode ,只要使用缓存的 hashcode 即可,这样一来大大提高了在散列集合中使用 String 对象的性能。

  2. String pool的需要
    当字符串不可变时,字符串常量池才有意义。字符串常量池的出现,可以减少创建相同字面量的字符串,让不同的引用指向池中同一个字符串,为运行时节约很多的堆内存。若字符串可变,字符串常量池失去意义,基于常量池的 String.intern() 方法也失效,每次创建新的字符串将在堆内开辟出新的空间,占据更多的内存。

  3. 安全性
    由于字符串无论在任何 Java 系统中都广泛使用,会用来存储敏感信息,如账号,密码,网络路径,文件处理等场景里,保证字符串 String 类的安全性就尤为重要了,如果字符串是可变的,容易被篡改,那就无法保证使用字符串进行操作时它是安全的,很有可能出现 SQL 注入,访问危险文件等操作。

  4. 线程安全
    在多线程中,只有不变的对象和值是线程安全的,可以在多个线程中共享数据。由于 String 天然的不可变,当一个线程”修改“了字符串的值,只会产生一个新的字符串对象,不会对其他线程的访问产生副作用,访问的都是同样的字符串数据,不需要任何同步操作。

String,StringBuffer,StringBuilder

1、String:是只读字符串,它并不是基本数据类型,而是一个对象。从底层源码来看是一个final类型的字符数组,所引用的字符串不能被改变,一经定义,无法再增删改。每次对String的操作都会生成新的String对象。
2、StringBuffer和StringBuilder:的底层都是可变的字符数组,所以在进行频繁的字符串操作时,建议使用StringBuffer和StringBuilder来进行操作。 另外StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。

  1. 可变性
  • String不可变
  • StringBuffer,StringBuilder可变
  1. 线程安全
  • String线程安全
  • StringBuffer线程不安全
  • StringBuilder线程安全,内部使用synchronized进行同步

字符串常量池

保存所有字符串字面量,在编译时期确定。
可以使用intern()方法,在运行过程中,将字符串添加到string pool中。如果已经存在,则返回引用,不存在,则添加一个新的字符串。

String str = "abc"创建对象的过程

1、首先在常量池中查找是否存在内容为"abc"字符串对象
2、如果不存在则在常量池中创建"abc",并让str引用该对象
3、如果存在则直接让str引用该对象

String str = new String(“abc”)创建实例的过程

1、首先在堆中(不是常量池)创建一个指定的对象"abc",并让str引用指向该对象
2、在字符串常量池中查看,是否存在内容为"abc"字符串对象
3、若存在,则将new出来的字符串对象与字符串常量池中的对象联系起来
4、若不存在,则在字符串常量池中创建一个内容为"abc"的字符串对象,并将堆中的对象与之联系起来

为什么有包装类

Java语言是面向对象的语言,其设计理念是“一切皆对象”。但8种基本数据类型却出现了例外,它们不具备对象的特性。正是为了解决这个问题,Java为每个基本数据类型都定义了一个对应的引用类型,这就是包装类。

Java之所以提供8种基本数据类型,主要是为了照顾程序员的传统习惯。这8种基本数据类型的确带来了一定的方便性,但在某些时候也会受到一些制约。比如,所有的引用类型的变量都继承于Object类,都可以当做Object类型的变量使用,但基本数据类型却不可以。如果某个方法需要Object类型的参数,但实际传入的值却是数字的话,就需要做特殊的处理了。有了包装类,这种问题就可以得以简化。

自动拆想装箱是什么

装箱:自动将基本数据类型转换为包装器类型(int–>Integer);调用方法:Integer的
valueOf(int) 方法
拆箱:自动将包装器类型转换为基本数据类型(Integer–>int)。调用方法:Integer的
intValue方法

Java SE5之前,如果要生成一个数值为10Integer对象,必须这样进行:
Integer i = new Integer(10);
而在从Java SE5开始就提供了自动装箱的特性,如果要生成一个数值为10Integer对象,只需要这样就可以了:
Integer i = 10;

通过自动装箱、自动拆箱功能,可以大大简化基本类型变量和包装类对象之间的转换过程。比如,某个方法的参数类型为包装类型,调用时我们所持有的数据却是基本类型的值,则可以不做任何特殊的处理,直接将这个基本类型的值传入给方法即可。

关键词

static用法

static关键字可以修饰成员变量、成员方法、初始化块、内部类,被static修饰的成员是类的成员,它属于类、不属于单个对象。

  • 类变量:被static修饰的成员变量叫类变量(静态变量)。类变量属于类,它随类的信息存储在方法区,并不随对象存储在堆中,类变量可以通过类名来访问,也可以通过对象名来访问,但建议通过类名访问它。
  • 类方法:被static修饰的成员方法叫类方法(静态方法)。类方法属于类,可以通过类名访问,也可以通过对象名访问,建议通过类名访问它。
  • 静态块:被static修饰的初始化块叫静态初始化块。静态块属于类,它在类加载的时候被隐式调用一次,之后便不会被调用了。
  • 静态内部类:被static修饰的内部类叫静态内部类。静态内部类可以包含静态成员,也可以包含非静态成员。静态内部类不能访问外部类的实例成员,只能访问外部类的静态成员。外部类的所有方法、初始化块都能访问其内部定义的静态内部类。
  • 静态导包,即 import static .import static是在JDK 1.5之后引入的新特性,可以用来指定导入某个类中的静态资源,并且不需要使用类名,可以直接使用资源名

final用法

final关键字可以修饰类、方法、变量,以下是final修饰这3种目标时表现出的特征:

  • final类:final关键字修饰的类不可以被继承。
  • final方法:final关键字修饰的方法不可以被重写。
  • final变量:final关键字修饰的变量,一旦获得了初始值,就不可以被修改。
  • final常量,在编译阶段会存入常量池。

父类子类构造函数,静态代码段,非静态代码段加载顺序

执行顺序为:静态代码块——>非静态代码块——>构造方法;

  1. 静态代码块总是最先执行的;
  2. 子类和父类的静态代码块都执行完之后,在执行父类的非静态代码块和父类的构造方法,最后执行子类的非静态代码块和构造方法.

静态代码块,在这个类加载的时候会执行,并且只执行一次,在创建对象之前会执行非静态代码块,并且在每次创建对象之前都会执行一次.

hashCode()的作用

java的集合有两类,一类是List,还有一类是Set。前者有序可重复,后者无序不重复。在set中插入时通过equals方法判断是否已存在该元素。但是如果元素太多,用这样的方法就会比较慢。
于是有人发明了哈希算法来提高集合中查找元素的效率。 这种方式将集合分成若干个存储区域,每个对象可以计算出一个哈希码,可以将哈希码分组,每组分别对应某个存储区域,根据一个对象的哈希码就可以确定该对象应该存储的那个区域。
hashCode方法可以这样理解:它返回的就是根据对象的内存地址换算出的一个值。这样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。

hashCode()和equals()

  1. what? 先解释这是干什么的
    - hashcode 是用来计算对象的 hash 值
    - equals 是用来判断对象是否等价的
    - 如果不重写 hashcode 和 equals 的话,调用的是父类 Object 类里的方法,其实就是把引用的地址值给返回出去。
  1. why? 为什么重写 equals 必须重写 hashcode 方法?
    - 因为我们规定等价的两个对象的 哈希值 一定相等,如果不重写 hashcode 的话,两个 new 出来的哈希肯定是不同的。
    - 举个例子:我们 HashSet 和 HashMap 底层都要使用对象的 hashCode 方法来计算桶下标,因此要将对象添加到这些集合里,必须重写 hashcode 和 equals 方法,不能只重写一个 equals,不然所有 new 出来的对象都判断为不是相等的对象。
  1. why? 为什么两个对象有相同的 hashcode 但不一定是相等的?
    - 因为 hashcode 函数是根据对象的内容计算出一个值,极端一点就和一个二次函数一样,输入不同的自变量对应相同的值。所以就要求 hashcode 函数设计的要够随机

有没有可能两个不相等的对象有相同的hashcode

有可能.在产生hash冲突时,两个不相等的对象就会有相同的 hashcode 值.当hash冲突产生时,一般有以下几种方式来处理:
1、拉链法:每个哈希表节点都有一个next指针,多个哈希表节点可以用next指针构成一个单向链表,被分配到同一个索引上的多个节点可以用这个单向链表进行存储。
2、开放定址法:一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入
3、再哈希:又叫双哈希法,有多个不同的Hash函数.当发生冲突时,使用第二个,第三个….等哈希函数计算地址,直到无冲突。

==和equal的区别

1、== 表示 判断2个变量或对象实例是否指向同一个内存空间,即判断它们是否为同一个对象
equals()表示 判断2个变量或对象实例所指向的内存空间的值是否相同。
2、== 表示 对内存地址进行比较,equals()表示 对字符串的内容进行比较。
3、== 表示引用是否相同,equals() 表示值是否相同。

浅拷贝和深拷贝

浅复制:仅仅是指向被复制的内存地址,如果原地址发生改变,那么浅复制出来的对象也会相应的改变。
深复制:在计算机中开辟一块新的内存地址用于存放复制的对象

值传递和引用传递

值传递:在调用函数时,将实际参数复制一份传递到函数中,这样在函数中对参数进行修改,就不会影响到原来的实际参数;
引用传递:在调用函数时,将实际参数的地址直接传递到函数中。这样在函数中对参数进行的修改,就会影响到实际参数;

向上转型和向下转型

类型转换:

  • 将一个类型强制转换成另一个类型的过程。
  • 对象类型转换,是指存在继承关系的对象。当对不存在继承关系的对象进行强制类型转换时,会抛出 Java 强制类型转换异常。
  • Java 中引用类型之间的类型转换主要有两种,分别是向上转型和向下转型。

向上转型

父类引用指向子类对象:实现接受参数的统一
fatherClass obj = new sonClass();
其中,fatherClass 是父类名称或接口名称,obj 是创建的对象,sonClass 是子类名称。

1.父类有的方法,都可以调用,如果被子类重写了,则会调用子类的方法。
2. 父类没有的方法,而子类存在,则不能调用。
3.向上转型只对方法有影响,对属性没影响。属性不存在重写。

减少重复代码,使代码变得简洁。
提高系统扩展性。
用于参数统一化,假设父类有n个子类,方法要接受子类的实例,如果没有向上转型,就需要定义n个方法接收不同的对象。

向下转型

子类对象指向父类引用:当父类需要调用子类的扩充方法时
sonClass obj = (sonClass) fatherClass;
fatherClass 是父类名称,obj 是创建的对象,sonClass 是子类名称。

向下转型之前一定要进行向上转型!!
否则在转型时会出现ClassCastException(类型转换异常–运行时异常)
解决:
先判断在转型(依靠instanceof关键字实现)引用名 instanceof 类 表示该引用是否能表示该类实例,返回boolean类型。
//per是否能表示Person实例
System.out.println(per instanceof Person);

总结

对象多态性的核心在于方法的覆写
通过对象的向上转型可以实现接受参数的统一,向下转型可以实现子类扩充的调用(一般不操作向下转型,有安全隐患)
两个没有关系的类对象是不能够转型的,一定会产生ClassCastException
多态就是同一个行为具有多个不同表现形式或形态的能力。
多态的分类:运行时多态和编译时多态。
运行时多态的前提:继承(实现),重写,向上转型与向下转型。

反射

定义

反射机制是在运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意个对象,都能够调用它的任意一个方法。在java中,只要给定类的名字,就可以通过反射机制来获得类的所有信息。
这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

应用场景

反射主要是用来获取运行时类的全部信息。
类在加载以后会在堆空间中放一个 Class 对象,我们可以通过 Class.forName() 方法通过全类名拿到这个 Class 对象,然后再配合 reflect 包下的 Method Filed Constructor 等方法获取类的全部信息。

  • 使用JDBC时,如果要创建数据库的连接,则需要先通过反射机制加载数据库的驱动程序;
  • 多数框架都支持注解/XML配置,从配置中解析出来的类是字符串,需要利用反射机制实例化;
  • 面向切面编程(AOP)的实现方案,是在程序运行时创建目标对象的代理类,这必须由反射机制来实现

实现方式:

第一步:获取Class对象,有4中方法:
1)Class.forName(“类的路径”);
2)类名.class
3)对象名.getClass()
4)基本类型的包装类,可以调用包装类的Type属性来获得该包装类的Class对象

实现Java反射的类:

1)Class:表示正在运行的Java应用程序中的类和接口
注意: 所有获取对象的信息都需要Class类来实现。
2)Field:提供有关类和接口的属性信息,以及对它的动态访问权限。
3)Constructor:提供关于类的单个构造方法的信息以及它的访问权限
4)Method:提供类或接口中某个方法的信息

实现如下的操作:

1、任意一个类的Class对象,并通过这个对象查看这个类的信息;
2、创建任意一个类的实例,并访问该实例的成员;
3、生成一个类的动态代理类或动态代理对象。

优缺点

优点:

  • 1)能够运行时动态获取类的实例,提高灵活性;
  • 2)与动态编译结合

缺点

  • 反射是非常慢的一种操作,并且反射能拿到包括私有属性在内的全部信息,所以也不是很安全。

泛型

定义:“泛型” 意味着编写的代码可以被不同类型的对象所重用。
提供了泛指的概念,但具体执行的时候却可以有具体的规则来约束,比如ArrayList就是个泛型类,ArrayList作为集合可以存放各种元素,如Integer, String,自定义的各种类型等,但在使用的时通过具体的规则来约束,如可以约束集合中只存放Integer类型的元素:

List<Integer> iniData = new ArrayList<>()

使用泛型的好处

以集合来举例,不必因为添加元素类型的不同而定义不同类型的集合,如整型集合类,浮点型集合类,我们可以定义一个集合来存放整型、浮点型数据,而这并不是最重要的,因为我们只要把底层存储设置了Object即可,添加的数据全部都可向上转型为Object。 更重要的是我们可以通过规则按照自己的想法控制存储的数据类型。

注解

异常类型

  • 顶层接口是 Throwable
  • Throwable 接口下又分为两种异常,
    1. 一个是 Error 是 JVM 处理不了的异常,比如 OOM 和 StackOverflow
    2. 一个是 Exception 程序可以自己处理的异常。
      a) 被检查异常 : Java编译器会检查它。 此类异常,要么通过throws进行声明抛出,要么通过try-catch进行捕获处理,否则不能通过编译。
      b) 运行时异常:Java编译器不会检查它。也就是说,当程序中可能出现这类异常时,倘若既"没有通过throws声明抛出它",也"没有用try-catch语句捕获它",还是会编译通过。例如除数为 0,空指针异常等等。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值