面向对象的三个特性:
- 封装
- 继承
- 多态
三大特性之封装
封装,隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数据。对外界而言,它的内部细节是隐藏的,暴露给外界的只是它的访问方法。
对于封装而言,一个对象所封装的是自己的属性和方法,所以不需要依赖其他对象就可以完成自己的操作。 三大好处:
- 良好的封装能降低耦合
- 类内部的结构可以自由修改
- 可以对成员进行精确的控制
- 隐藏信息,实现细节
三大特性之继承
继承所描述的是**“is-a”**的关系,如果有两个对象A和B,若可以描述为“A是B”,则可以表示A继承B,其中B被继承者称之为父类或者超类,A是继承者称之为子类或者派生类。
实际上,子类是父类的特殊化,它除了拥有父类的特性外,还拥有自己独有的特性。同时继承关系中,子类可以替代父类,反之不行,例如猫是动物,但不能说动物就是猫。
使用继承需注意三句话:
- 子类拥有父类非private的属性和方法
- 构造函数,只能被调用(super()),不能被继承
- 子类可以拥有自己的属性和方法,即子类可对父类进行扩展
- 子类可以用自己的方式实现父类的方法
继承的缺点
- 父类边,子类必须变
- 继承是一种强耦合关系
- 继承破坏了封装(对于父类而言,它的实现细节对于子类来说完全透明)
三大特性之多态
多态,指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定。
实现多态的三个必要条件:
- 继承,在多态中必须存在继承关系的子类和父类
- 重写,子类对父类中某些方法进行重新定义(重写),在调用这些方法时就会调用子类的方法
- 向上转型,在多态中将子类的引用赋给父类对象,只有这样才能够具备既能调用父类的方法,又能调用子类的方法
实现多态的形式:
- 继承,通过重写(重新定义)父类的同一方法的几个不同子类来体现的
- 接口,通过实现接口中同一方法的几个不同类体现的
另外,在继承链中对象方法的调用,存在一个优先级: this.show(O) -> super.show(O) -> this.show((super)O) -> super.show((super)O)
四舍五入方法
方法一(BigDecimal)
使用BigDecimal,并且采用setScale()方法来设置精确度,同时使用RoundingModel.HALF_UP表示数字舍入法则。
double f = 111231.5473;BigDecimal b = new BigDecimal(f);double r = b.setScale(2, RoundingModel.HALF_UP).doubleValue();
方法二(DecimalFormat)
java.text.DecimalFormat df = new java.text.DecimalFormat(" #.00");df.format(需要格式化的数字);
注: #.00,表示两位小数 #.0000,表示四位小数
方法三(String.format("%.2f", Object obj))
double d = 3.1415926;String result = String.format("%.2f", d);
%.2f,%.表示小数点前任意位数, 2表示两位小数,格式后的结果为f,表示浮点型
抽象类和接口
抽象类注意点:
- 抽象类不能实例化,实例化的工作应该由其子类完成,它只需要一个引用即可
- 抽象方法必须由子类完成
- 只要包含抽象方法的类,必为抽象类,不管是否包含其他方法
- 抽象类中可以包含具体的方法,也可以不包含抽象方法
- 子类中的抽象方法不能与父类的抽象方法同名
- abstract不能与final并列修饰同一个类
- abstract不能与private、static、final或native并列修饰同一方法
接口,本身就不是类,是抽象类的延伸。 接口注意点:
- 接口中所有方法的访问权限自动被声明为public
- 接口中只存在public static final类型的成员变量
- 接口中不存在具体实现的方法
- 实现接口的非抽象类必须要实现所有接口方法
- 接口不能实例化,但可以声明一个接口变量,该变量必须引用一个实现该接口的类实例
- 实现多接口时一定要避免方法名的重复
关键字static
被static修饰的成员变量和方法是独立于该类的,不依赖与某个特定的实例对象,也就是被该类的所有实例对象共享。所有实例对象的引用都指向同一个地方,任何一个实例对其的修改都会导致其他实例的变化。
static变量
static修饰的变量称之为静态变量,没有用static修饰的成为成员变量。区别是:
- 静态变量,随着类的加载完成初始化的,内存中仅有一个,且JVM只会为其分配一次内存,同时类的所有实例对象共享该变量
- 实例变量,是伴随着类的实例对象的,没创建一个实例就会产生一个实例变量,它与该实例同生共死
static方法
static修饰的方法,为静态方法,通过类名对其进行直接调用。在类加载时就存在了,不依赖于任何实例对象,所以static方法必须实现,不能是抽象方法abstract
static代码块
被static修饰的代码块,成为静态代码块,随着类的加载一并执行,而且可以随意放
static局限性
- 只能调用static变量
- 只能调用static方法
- 不能以任何形式引用this、super
- static变量定义时必须要进行初始化,且初始化时间要早于非静态变量
内部类
将一个类的定义放在另一个类的定义内部,这就是内部类。
使用内部类的原因:每个内部类都能独立地继承一个接口的实现,所以无论外围类是否已经继承了某个接口的实现,对于内部类都没有影响。
接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。
内部类基础
当我们创建一个内部类的时候,它无形中就与外围类有了一种联系,依赖于这种联系,它可以无限制地访问外围类的元素。
内部类的分类
java中内部类主要分为:
- 成员内部类
- 局部内部类
- 匿名内部类
- 静态内部类
- 成员内部类,最普通的内部类
成员内部类,是外围类的一个成员,所以它是可以无限制的访问外围类的所有成员属性和方法,尽管是private,但是外围类要访问内部类的成员属性和方法则需要通过内部类的实例来访问。
使用注意:
- 成员内部类中不能存在任何static修饰的变量和方法
- 成员内部类依附于外围类的,所以只有先创建了外围类才能够创建内部类
- 推荐使用getXXXX()获取成员内部类,尤其是该内部类的构造函数无参数时
- 局部内部类
局部内部类,嵌套在方法的作用域内,对于这个类的使用主要是应用与解决比较复杂的问题,想创建一个类来辅助我们的解决方案,但又不希望这个类是公用的。
- 匿名内部类
- 匿名内部类没有任何访问修饰符
- new 匿名内部类,这个类首先是要存在的
- 当所在方法的形参需要被匿名内部类使用,那此形参必须为final
- 匿名内部类是没有构造方法的
- 静态内部类
使用static修饰的内部类,称之为静态内部类。静态内部类与非静态内部类之间存在一个最大的区别:非静态内部类在编译完成后会隐含地保存着一个外围类的引用,但是静态内部类没有。意味着:
- 静态内部类的创建,不需要依赖于外围类
- 不能使用任何外围类的非static成员变量和方法