类为什么不能老老实实的?
Posted 塞蒙
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了类为什么不能老老实实的?相关的知识,希望对你有一定的参考价值。
在《再谈面向对象》里边写了关于面向对象的一些基本语法,比如类里有成员变量和方法,还有构造方法,而且类还能通过访问修饰符修饰成员变量和方法,已达到封装的目的,类还能通过extends关键字实现继承,还能通过向上转型实例化对象实现多态,这一切看起来很美好,没有是没问题了,世界都可以用Java描述了,但是Java的基本规则不仅如此,还有很多其他特性,比如Java还提供了8个基本类型对应的包装类,final关键字,abstract修饰的抽象类和interface定义的接口等,enum关键字定义的枚举类,还有集合,泛型,还要进行异常处置,Java类为什么不能老老实实的,本文就来回答10个为什么?
1、为什么有这三个关键字?
this关键字是为了偷懒!Java提供了一个this关键字,这个关键字总是指向调用该方法的对象。若是在构造器中使用就是在引用构造器正在初始化的对象的成员,而不是构造器本身的参数。但是方法引用本类中的其他方法的时候可以省略this,所以这就起到了偷懒的作用,使得在内的内部调用方法的时候,好像不是对象在调用,但是其实还是this对象在调用。
static关键字是为了实现在栈内存中定义方法和变量的功能。但是如果方法被static修饰,这个方法就存在于栈内存中,不能使用this调用。并且static修饰的静态成员不能访问非静态成员。也就是static修饰的方法是类的方法,没有static修饰的方法是实例的方法。
final关键字是为了实现使得类,变量和方法不变的功能。final变量相当于宏替代:修饰变量的时候根据变量种类的不同,可以分为多种,可以修饰成员变量,形参,局部变量,但是这些变量必须被赋值(不指定初值会默认分配0,nill变得没有意义)。final修饰的变量不能被改变,一旦获得初值,就不会改变。final类没有子类final方法不能被重写
2、为什么要有包装类?
这个问题其实不影响Java类的特性,包装类只是8个Java基本类库中的比较特殊的类。8种基本数据类型没有“对象特性”,因此不能被调用,因此Java提供了8种包装类Byte/Short/Integer/Long/Character/Float/Double/Boolean,Java提供了自动装箱和自动拆箱机制,有了这个机制之后,基本数据类型定义的变量实际上就有了像是对象一样的特性,可以被随时调用。
这只是包装类的一个功能,包装类的另一个功能就是实现基本数据类型个String字符串之间的转换。
/* 本类是为了演示String和基本数据类型之间的转换,没有实际意义, */ public class Primitiive2String{ public static void main(String [] args){ /* *特定int字符串个转换为int */ String intStr="123"; int it1=Integer.parseInt(intStr);//利用了包装类的parseInt方法 int it2=new Integer(intStr);//利用了包装类的Integer(String)构造器 System.out.println(it1); /* *特定float字符串个转换为float */ String floatStr="12.1"; float it3=Float.parseFloat(floatStr);//利用了包装类的parseInt方法 float it4=new Float(floatStr);//利用了包装类的Integer(String)构造器 System.out.println(it3); /* *float转换为String */ String ftStr =String.valueOf(23.65f);//利用String的valueOf(基本数据类型)函数,valueOf函数是一个重载函数,支持所有的基本数据类型 System.out.println(ftStr); String booleanStr=String.valueOf(true); System.out.println(booleanStr); } }
要熟知可以通过包装类的String类型参数构造器构造一个基本数据类型和通过包装类的parseXxx(String)方法两种方式转化为基本数据类型,已经通过包装类的valueOf()方法转化为字符串。
3、为什么还可以有两个类成员?
类成员其实除了属性,方法和构造方法还能有另外的两个,就是
- 初始化块。当创建Java对象,系统会先调用初始化块。初始化块是只有创建对象时候隐式执行的,初始化块是构造函数的辅助。可以把每次初始化对象的时候在构造器中执行的相同的代码提到初始化块中。
- 内部类(内部接口,内部枚举类)。内部类是一种封装性更好的类,通常定义一些脱离了外部类没什么意义的类。内部类的存在是为了解决逻辑上的寄宿关系的问题,并且能在类上实现private和static这种关键词的功能。必须搞清楚内部类和外部类的关系,内部类可以看成是外部类的一部分。
-
- 内部类可以访问外部类的私有成员,但是外部类不能访问内部类的成员变量,但是可以调用内部类的public方法。
- 内部类可以用private,protected,static关键字修饰,外部类则不能。
- 非静态内部类不能拥有静态变量。
- static修饰的内部类属于外部类本身。静态内部类只能访问外部类的静态成员。
4、为什么要有不可变类?
不可变类就是指,创建了该类的对象之后,对象变量是不可变的。封装的作用就是利用setter和getter控制度private成员变量的访问权限,不可变类就是不提供这些方法的类,这样的类的存在是为了实现不可变的功能。值得注意的是,8个包装类和String类都是不可变类,也就是对象一旦被赋值,就不会改变。
5:为什么要有抽象类和接口?
有时候定义父类的时候,比如定义一个形状类,形状类应该提供周长的方法,但是,子类的周长方法可能很不相同,所以应该写周长方法,但是又没法写,这时候最好把父类定义成抽象类,这样父类提供了方法签名,但是没有方法实现。抽闲类的存在是为了体现现实生活中的这种逻辑关系。
抽象类必须使用abstract修饰符定义,抽象类不能被实例化,抽象方法必须存在于抽象类中,可以用有得有失四个字描述,得是指可以在其中创建抽象方法,失是指不能被实例化。
抽象类体现了一种模板模式的设计,如果把抽象类的思想进行的更彻底,也就是所有的方法都是抽象方法,这就是接口。
接口的定义不再使用class关键字,而是使用interface关键字,接口也可以继承接口,而且可以继承多个接口,继承后将获得所有的常量和方法。接口中只能有三种元素,那就是静态常量,抽象方法,内部类。接口里的成员变量默认为public static final修饰。方法默认为public abstract修饰。
接口被实现用implements关键字,implements关键字必须放在extends之后。
但是接口在思想上主要体现标准和规范,也就是说必须向外界提供哪些服务。
抽象类则主要体现模板设计的思想。
面向接口编程:这里就涉及到了设计模式的问题,关于设计模式,不能简单地抱着一本书来看,而是要在编程的过程中经历某种痛苦,再把设计模式当做工具书,因为设计模式就是对经常出现的软件设计问题的成熟的解决方案。
6:为什么要有枚举类?
枚举类的存在是为了表示现实生活中的这种存在:一个类的对象个数是确定的。比如星型只有8个,比如季节只有4个。
Java为了实现类的实例只能是特定的值(枚举值)的功能,新加了一个关键字:enum。用这个关键字实现现实生活中这种特殊的类。
- 默认继承了java.lang.Enum类,而不是Object类,因此可以实现一个或多个接口,但是不能显示继承其他父类。
- 枚举类默认是final修饰的类,所以不能被继承。
- 构造器只能使用private修饰符,或者默认也是pribate修饰符。
- 枚举类的所有实例必须在第一行显示。
- 最大的区别就是实例化对象的语法不同。只能使用valueOf方法实例化枚举类的对象。
- 也可以实现接口,也可以写抽象方法
7:为什么要有集合类?
说白了就是Java数据结构的实现、是一种特殊的类,也就是实现一些功能,这些功能就是保存数量不定,并且具有映射关系的数组,也称为容器类。集合类都位于java.util包中。关系主要有Set\\List\\Queue\\Map四种体系,其中Set\\List\\Queue是继承Collection接口的,Set是无序,不可重复的集合,List代表有序重复的集合,Queue是类似于Java的队列实现,Map是代表具有映射关系的集合。
- 只能保存对象,不能保存基本类型
- 主要有Collection和Map两个接口派生而成。
Map保存的每项数据都是key-value对。
8:为什么要有泛型?
Java泛型是发展的结果,Java支持泛型很大程度上是为了让集合能记住元素的数据类型。核心思想在于,在定义类、接口、方法的时候,可以使用一个标记,此标记在代表类型,这个类型在声明变量,创建对象和调用方法时动态的指定。是为了实现动态指定类型的功能。泛型类就是普通类的工厂,在实例化对象的时候生产相应类型的类,泛型接口就是普通接口的工厂,在实现接口的时候生产相应类型的类,泛型方法就是普通方法的工厂,在调用方法的时候生产相应类型的方法。
9:为什么要有异常处理?
在没有异常处理的语言中,通常需要大量的判断语句,配合所想到的错误来捕获程序中所有可能发生的错误。Java的异常处理机制实现了优雅的处理代码的异常,增进程序的稳定性和效率的功能。
Java的异常处理机制:
- 一旦产生异常,则首先会产生一个异常类的实例化对象。
- 在try语句中对此异常对象进行捕获。
- 产生的异常对象与catch语句中的各个异常类型进行匹配,如果匹配成功,则执行catch语句中的代码。
- finaly是异常的统一出口,一定会执行。
- throws:使用throws声明的方法表示此方法不处理异常,而交给方法的调用处进行处理。
- 可以直接使用throw关键字人为的抛出一个异常,抛出时,直接抛出异常类的实例化对象即可。
10:为什么要有Annotation?
对Java程序开发而言,把配置信息写在程序里,但是有明显的标记信息,这就叫做Annotation。
但是只有学会了反射之后,才能很好的利用Annotation。但是Java提供了基本的5个Annotation,位于java.lang里,使用的时候就当做修饰符使用,前面加@:
- @Override:限定重写父类方法
- @Deprecated:标注已过时
- @SupperssWarnings:抑制编译器警告
- @SafeVarargs:Java7新增,“堆污染”警告
- @FunctionalInterface:Java8新增。函数式接口。
Annotation可以为程序提供一些元数据,这些元数据在编译,运行时被读取,从而提供更多的额外的处理信息。
以上是关于类为什么不能老老实实的?的主要内容,如果未能解决你的问题,请参考以下文章