摘要:使用创建的字符串对象是运行时创建出来的,它被保存在运行时内存区,即堆内存,不会放入常量池中。类成员创建的对象实例中根本不会拥有对应类的类变量。抽象类的构造器不能用于创建实例,主要是用于被其子类调用。
Java提供了final关键字来修饰变量,方法和类,系统不允许为final变量重新赋值,子类不允许覆盖父类的final方法,final类不能派生子类。
Abstract 和 interface两个关键字分别用于定义抽象类和接口,抽象类和接口都是从多个子类中抽象出来的共同特征,但抽象类主要作为多个类的模板,而接口则定义了多类应该遵守的规则。
基本数据类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
char | Character |
double | Double |
float | Float |
boolean | Boolean |
自动装箱,就是把一个基本类型变量直接赋值给对应的包装类变量,或者OBJECT。
自动拆箱,允许直接把包装类对象直接赋值给一个对应的基本类型变量。
包装类型的变量是引用数据类型,但包装类的实例可以与数值类型的值作比较,这种比较是直接取出包装类实例所包装的数值来进行比较的。
两个包装类实例比较,只有两个包装类引用指向同一个对象才会返回true。
对于Integer包装类型的数值超过了(-128 --- 127)比较为false的解释如下:
系统会把一个-128到127之间的整数自动装箱成Integer实例,并放入了一个名为cache的数组中缓存起来,如果以后把一个-128到127之间的整数自动装箱成一个Integer实例的时候,实际上是直接指向对应的数组元素,因此-128到127之间的同一个整数自动装箱成Integer实例时,永远都是引用此cache数组的同一个数组元素,所以他们全部相等,但每次把一个不在-128到127范围内的整数自动装箱成Integer实例时,系统总是重新创建一个Integer实例,所以比较为false。
public static void main(String[] args) {
Integer valueOf = 112; Integer valueOf1 = 112; //dsds : true System.out.println("dsds : "+(valueOf == valueOf1)); Integer valueOf2 = 128; Integer valueOf3 = 128; //dsds : false System.out.println("dsds : "+(valueOf2 == valueOf3));
}
Boolean值的比较:true > false
处理对象当使用==来判断两个变量是否相等时,如果两个变量是基本类型,且都是数值类型,则只要两个变量的值相等就会返回true。
对于两个引用变量必须引用一个对象的时候==才会返回true,==不可用于比较类型上没有父子关系的两个对象。
常量池:constant pool,专门用于管理在编译时被确定并且被保存在以编译的.class文件中的一些数据。包括了关于类,方法,接口中的常量,还包括字符串常量。
JVM常量池保证相同的字符串直接量只有一个,不会产生多余副本。
使用new String()创建的字符串对象是运行时创建出来的,它被保存在运行时内存区,即堆内存,不会放入常量池中。
类成员创建的对象实例中根本不会拥有对应类的类变量。
Null对象可以访问他所属类的类成员。
类成员不能访问实例成员,包括成员变量,方法,初始化块,内部类和枚举类。因为类成员是属于类的,类成员的作用域比实例成员的作用域更大,完全可能出现类成员已将初始化完成,但实例成员还不曾初始化的情况,如果允许类成员访问实例成员将会引起大量错误。
如果一个类始终只能创建一个实例,那就被成为单例类。
为了避免其他类自由创建该类的实例,应该把构造器private修饰,从而把该类的所有构造器隐藏起来。
一旦把该类的构造器隐藏起来,就需要提供一个public方法作为该类的访问点,用于创建该类的对象,且该方法必须使用static修饰。除此之外,该类还必须缓存已经创建的对象,否则该类无法知道是否曾经创建过对象。
代码实例
public class Singleton { //单例类 public static Singleton singleton;//用于保存创建好的对象。 private Singleton() {}//private修饰,对外隐藏构造器 public static Singleton getInstance() { if (singleton == null) {//如果为空那么就是未曾创建对象 singleton = new Singleton();//创建对象 } return singleton;//返回 } public static void main(String[] args) { Singleton instance = Singleton.getInstance(); Singleton instance1 = Singleton.getInstance(); System.out.println(instance == instance1);//true } }Final修饰符
当类初始化时,系统会为该类的类变量分配内存,并分配默认值,当创建对象时,系统会为该对象的实例变量分配内存,并分配默认值,也就是说:当执行静态初始化快时可以对类变量附初始值,当执行初始化代码块,构造器时可以对实例变量附初始值。
Final修饰的成员变量而言,一旦有了初始值,就不能二次赋值,如果既没有初始值,也没有在构造器,初始化块中指定初始值,那么就为系统默认的初始值,也就失去了意义,因此final修饰的成员变量必须由程序员显示的指定初始值。
Final修饰的类变量,实例变量能指定初始值的地方
类变量:必须在静态初始化块中指定初始值或声明该类变量时指定初始值。
实例变量:非静态初始化块,声明变量时和构造器中。
实例变量不能在静态初始化块中指定初始值,因为静态初始化块是静态成员,不可访问实例变量-非静态成员。类变量不能在普通初始化块中指定初始值,因为类变量在类初始化阶段已经被初始化了。
Final成员变量在显示初始化之前不能直接访问,但可以通过方法来访问,基本可以算是java的一个设计缺陷。
系统不会对局部变量初始化,局部变量必须由程序员显示初始化,因此使用final修饰局部变量时。既可以在定义时指定默认值,也可以不指定默认值。
当使用final修饰基本类型变量时,不能对基本类型变量重新赋值,因此基本类型变量不能被改变。但对于引用变量而言,他仅仅保存的是一个引用,final只保证这个引用类型变量所引用的地址不会改变,即一直引用同一个对象,但是在堆内存中的这个对象完全可以发生改变。
宏变量的确定条件
使用final修饰。
在定义该final变量时就指定了初始值。
该初始值可以在编译时被确定下来。
宏变量一旦确定下来,编译器会把程序中所有用到该变量的地方直接替换成该变量的值。
宏变量与非宏变量不相等
不希望子类冲重写父类的某个方法,则可以使用final修饰该方法。
为了保证某个类不被继承,则可以使用final修饰这个类。
不可变类:创建实例后,实例的实例变量是不可改变的。如Integer in = new Integer(8);
创建自定义的不可变类规则如下
使用private和final修饰符来修饰该类中的成员。
提供带参数的构造器,用于传入参数以便初始化成员变量。
仅为该类的成员变量提供getter方法,不要为该类提供setter方法,因为普通方法无法修改final修饰的成员变量。
如果有必要重写Object中的equals 和 hashCode方法
与可变类相比,不可变类的实例在整个生命周期中要永远处于初始化状态,他的实例变量不可以改变,因此对不可变类的实例的控制更加简单。
public class NoChangeClass { private final ClassNames names; public NoChangeClass() { this.names = new ClassNames("1","2");//默认值 } public NoChangeClass(ClassNames names) { //如果利用有参构造,那么直接new一个新实例,这样避免了旧实例的更改造成当前类的变化。 this.names = new ClassNames(names.getName(),names.getTime()); } public ClassNames getNames() { return new ClassNames(names.getName(),names.getTime()); } public static void main(String[] args) { ClassNames classNames = new ClassNames("?","??"); NoChangeClass noChangeClass = new NoChangeClass(classNames); System.out.println(classNames.getName()); classNames.setName("21e1231"); System.out.println(classNames.getName()); System.out.println(noChangeClass.names.getName()); } } Output: ? 21e1231 ?抽象类
某个父类只是知道其子类应该包含怎么样的方法,但是无法准确的知道这些子类是如何实现这些方法的。
抽象方法只有方法签名,没有方法实现的方法。
有抽象方法的类只能被定义为抽象类,抽象类可以没有抽象方法。
抽象方法和抽象类的规则
抽象类抽象方法必须使用abstract修饰符修饰,抽象方法不能有方法体。
抽象类不能被实例化,无法使用new调用抽象类的构造器创建抽象类的实例,即使抽象类里不包含抽象方法。
抽象类可以包含成员变量,方法,构造器,初始化块,内部类。抽象类的构造器不能用于创建实例,主要是用于被其子类调用。
含有抽象方法的类,包括直接定义了一个抽象方法;或者集成了一个抽象父类,但没有完全实现父类包含的抽象方法;或实现了一个借口,但没有完全实现接口包含的抽象方法,只能被定义为抽象类.
在创建其子类实例的时候调用抽象父类的构造器,初始化块。
抽象类不能用于创建实例,只能当做父类被其他子类继承。
Abstract修饰类,表示只能被继承,修饰方法,表明必须由子类实现重写。而final修饰的类不能被继承,final修饰的方法不能被重写,所以final和abstract不能同时修饰类和方法。
Static与abstract不能同时修饰某个方法,即没有所谓的类抽象方法。但是可以同时修饰内部类。
Abstract关键字修饰的方法必须被其子类重写才有意义,否则就永远不会拥有方法体,所以abstract方法不能是private修饰。Private与abstract不能同时修饰方法。
抽象类是从多个具体类中抽象出来的父类,它具有更高层次的抽象。
抽象类模板模式的简单规则:
抽象父类可以只定义需要使用的某些方法,把不能实现的部分抽象成抽象方法,留给其子类去实现。
父类中可能包含需要调用其他系列方法的方法,这些被调用方法即可以由父类实现,也可以由其子类实现。父类里提供的方法只是定义了一个通用算法,其实现也许并不完全由自身实现,而必须依赖于其子类的辅助。
Java 9 改进的接口Java9对接口进行了改进,允许在接口中定义默认方法和类方法。
接口定义的是多个类共同的公共行为规范,这些行为是与外部交流的通道,这就意味着接口里通常是定义一组公共方法。
接口定义的基本语法说明:
修饰符可以是public或者省略,如果省略了public,则默认采用包权限访问控制符。
一个接口可以有多个直接父接口,但接口只能继承接口,不能继承类。
由于接口定义的是一种规范,因此接口里不能包含构造器和初始化块定义,可以包含常量(静态常量),方法(只能是抽象实例方法,类方法,默认和私有方法),内部类定义。
接口中的私有方法可以拥有方法体,但私有方法不能使用default修饰。私有方法可以使用static修饰,所以就是说私有方法可以是类方法也可以是实例方法。
接口中的静态常量是接口相关的。因此默认增加static和final修饰符。所以在接口中的成员变量总是使用public static final修饰,并且只能在定义时指定初始值。
接口中如果不是定义默认方法类方法或私有方法,系统自动为普通方法增加abstract修饰符。接口中的普通方法总是使用public abstract修饰。
接口中定义的内部类,内部接口,内部枚举默认都采用public static两个修饰符,不管定义时是否指定,系统会为其自动修饰。
默认方法都是采用default修饰,不能使用static修饰,并且总是public修饰。需要使用接口的实现类实例来调用这些方法。
类方法总是public修饰,可以直接使用接口名来调用。
接口中的默认方法:当两个默认方法中包含一段相同的实现逻辑时,就有必要把这段代码抽取成工具方法,而且工具方法一般是被隐藏的,所以这就是java9中增加私有方法的原因。
一个接口可以由多个直接父接口,和类继承相似,子接口扩展某个父接口时,将会获得父接口里定义的所有抽象方法,常量。
接口不能用于创建实例,但是可以用于声明引用型变量。
接口的主要用途就是被实现类实现:
定义变量,也可以用于强制类型转换。
调用接口中定义的常量、
被其他类实现。
实现接口与继承父类相似,一样可以获得所实现接口里定义的常量,方法,
一个类实现了一个或者多个接口之后,必须完全实现接口中定义的全部抽象方法,否则该类就将保留从父接口集成得到的抽象方法,该类也必须定义成抽象类。
一个类实现某个接口时,该类将会获得接口中定义的常量,方法等。因此可以把实现接口理解为一种特殊的继承。相当于实现类继承了一个彻底抽象的类。
为什么实现类实现接口里的方法只能使用public?
因为接口里的方法都是public的,而子类重写父类方法时访问权限只能更高或者相等。
抽象类即只对事物本身的抽象,接口则是对事物本身拥有的行为的抽象。
接口与抽象类的在用法上的差别。:
接口里只能包含抽象方法,静态方法,默认方法和私有方法。不能为普通方法提供实现,抽象类完全可以。
接口里只能定义静态常量,不能定义普通成员变量,抽象类都可以。
接口里不包含构造器;抽象类里可以包含构造器,抽象类里的构造器并不是用于创建对象。而是让其子类调用这些构造器来完成属于抽象类的初始化操作。
接口里不能包含初始化块,但抽象类则完全可以包含。
一个类最多只能有一个直接父类,包括抽象类。但一个类可以实现多个接口,通过实现多个接口可以弥补java单继承的不足。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/69292.html
摘要:面向对象与面向过程的区别要知道,二者并不是非此即彼,而是相辅相成的。而面向过程,则在微观上对对象内部进行具体的实现。面向对象的三大特性说到面向对象,就不得不说其三大特性封装继承和多态。封装封装是面向对象最基础的特性。 作者:伯特出处:github.com/ruicbAndroid/LoulanPlan声明:本文出自伯特的《LoulanPlan》,转载务必注明作者及出处。 刚学习 Jav...
摘要:二面向对象概述面向过程的设计思想和面向对象的设计思想我要吃鱼香肉丝盖饭面向过程我买菜我洗菜我切菜我放水我点火我做饭我炒菜。。。。 大家好,上次我们讲过了乐字节Java编程之方法、调用、重载、递归,接下来我们将会进入到Java封装的内容。Java编程语言发展,面向对象和类。 一、编程语言的发展 机器语言——直接由计算机的指令组成,指令、数据、地址都以0和1组成:可以被计算机直接识别并执行...
摘要:是一种典型的面向对象编程语言。这篇文章主要是来初步理解一下面向对象的思维为下面的内容先给一个基础。针对面向对象编程的更多内容,会在后面的文章里面详细解释。他们都称之为对象。之后,我们再用编程语言,把这种映射编写出来,就是的面向对象编程啦。 showImg(https://segmentfault.com/img/remote/1460000012983458?w=900&h=500);...
摘要:众多面向对象的编程思想虽不尽一致,但是无论哪种面向对象编程语言都具有以下的共通功能。原型编程以类为中心的传统面向对象编程,是以类为基础生成新对象。而原型模式的面向对象编程语言没有类这样一个概念。 什么是面向对象?这个问题往往会问到刚毕业的新手or实习生上,也是往往作为一个技术面试的开头题。在这里我们不去谈如何答(fu)好(yan)问(guo)题(qu),仅谈谈我所理解的面向对象。 从历...
摘要:对象既是该类事物实实在在存在的个体。类与对象的关系图类就是汽车汽车就是堆内存中的对象。成员变量成员变量成员函数的车,轮胎数个,跑起来了对象的创建创建对象中创建对象,使用关键字在堆内存中开辟了空间,产生了一个实体。 声明:本文首发于我的个人微信公众号【Java编程社区】,查看更多文章与学习资源请移步我的公众号Java编程社区 万物皆对象 学习Java,我们都听过这句话:万物皆对象。那么什...
摘要:知识点总结面向对象知识点总结面向对象面向对象概念是相对于面向过程而言,过程其实就是函数,对象是将函数和属性进行了封装。指向了该对象关键字代表对象。静态变量所属于类,所以也称为类变量成员变量存在于堆内存中。 Java知识点总结(面向对象) @(Java知识点总结)[Java, Java面向对象] [toc] 面向对象概念 是相对于面向过程而言,过程其实就是函数,对象是将函数和属性进行了封...
阅读 1829·2021-11-11 16:54
阅读 2055·2019-08-30 15:56
阅读 2364·2019-08-30 15:44
阅读 1280·2019-08-30 15:43
阅读 1855·2019-08-30 11:07
阅读 812·2019-08-29 17:11
阅读 1464·2019-08-29 15:23
阅读 3006·2019-08-29 13:01