java基础--面向对象4

来源:互联网 发布:sql 设置列默认值 编辑:程序博客网 时间:2024/06/05 12:31

 1.字段不存在多态

上节讲了继承和多态,那字段是否也存在多态呢:

 

class Super {public String name = "super.class";public void doWork() {System.out.println("super.dowork");}}class SubClass extends Super {public String name = "sub.class";public void doWork() {System.out.println("sub.dowork");}}public class FieldDemo {public static void main(String[] args) {Super clz = new SubClass();clz.doWork();//sub.doworkSystem.out.println(clz.name);//super.class}}

通过对象调用字段,在编译时期就已经觉得了调用哪一个块内存空间的数据,

----------------------->字段不存在覆盖的概念,在多态时候,不能有多态特征(在运行时期体现子类特征)

当子类和父类存在相同的字段时候,无论修饰符是什么.即使是private,都会在各自的空间中存储数据.


什么是代码块:

在类或者方法中,直接使用”{}”括起来的一段代码,表示一块代码区域

代码块里变量属于局部变量,只是在自己所在区域(前后的{})有效.

根据代码块定义的位置不同,我们分为三种形式:

(1)局部代码块:直接定义在方法内部的代码块:

 //代码块class CodeBlockDemo{public static void main(String[] args) {System.out.println("Hello world!");{//局部代码块int age = 17;System.out.println(age);}}}


一般我们不会直接使用局部代码块的,会结合if,while,where等关键字联合,表示一块代码区域

(2)初始化代码块(构造代码块):直接定义在类中

每次创建对象的是时候都会执行初始化代码

每次创建对象都会调用构造器,但是在调用构造器之前,会先执行本类中的初始化代码块

(3)静态代码块:使用static修饰的初始代码块

在主方法之前执行静态代码块,且只执行一次

Main方法是程序的入口,为什么静态代码块优先于main方法

--->静态成员随着字节码的加载而加载到jvm,此时main方法还未执行,因为方法需要jvm调用

先把字节码加载到jvm,而后jvm在调用main方法

我们一般用来作初始化操作,加载资源


为什么要是用final修饰符:

继承关系最大的弊端是破坏封装,子类能访问父类的实现细节,而且可以通过方法覆盖的形式修改实现细节

------------------------------------------------------------

多个修饰符直接是没有先后关系的. public static final / public static final

--------------------------------------------------------------------------------------------------

final本身的含义是 “最终的不可改变的”,它可以修饰非抽象类,非抽象方法和变量.

注意:构造方法不能够使用final修饰,因为构造方法不能被继承,肯定是最终的.

 

Final修饰的类:最终的类,不能再有子类

fianl class SuperClass{}class SubClass extends SuperClass//FinalDemo.java:5:错误:无法从最终SuperClass进行继承{}

满足以下条件就可以把一个类设计成final:

(1)某类不是专门为继承而设计的

(2)出于安全考虑,类的实现细节不允许改的,不准修改源代码

(3)明确该类不会被再拓展

列举java中内置所用final修饰的类

Java内用final修饰的类有很多,例如八大基本数据类型保证类和string

------------------------------------------------------------------------------------------------------------

Final修饰的方法:最终的方法,该方法不能被子类覆盖.

什么时候的方法需要使用final修饰.

(1)在父类中提供的统一的算法骨架,不准子类通过方法覆盖来修改时候,此时使用final修饰,模板方法设计模式

(2)构造器中调用的方法(初始化方法),初始化方法一般使用final修饰

 

Final修饰的方法,子类可以调用,但是不能覆盖  

class SuperClass{final public void doWork(){}}class SubClass extends SuperClass{public void doWork();//错误:SubClass 的doWork()无法覆盖SuperClass中的doWork(){}}

-----------------------------------------------------------------------------------------------------------------

Final修饰的变量:表示常量,只能赋值一次,不能再赋值

 

(1)Final变量必须显式的指定初始值,系统不会给final字段初始化

(2)Final变量一点赋予初始值,就不能被重复赋值

 class FinalDemo {final static String name = null;public static void main(String[] args) {name = "bb";//错误:无法为最终变量name分配值System.out.println(name);}}

(3)常量名规范: 常量名符号标识符,单词全部大写,单词键使用下划线隔开

  Int 类型的最大值: final int MAX_VALUE = ...;

  补充:全局静态常量 public static final 修饰的变量,直接使用类名调用即可.

------------------------------------------------------------------------------------------------------------------

面试题:final修饰的引用类型变量到底表示引用的地址不能改变,还是引用的空间中的数据不能改变

Final修饰的基本类型变量:表示变量的值不能改变,不能用=号重复赋值

Final修饰的引用类型变量:表示该变量的引用地址不能变,而不是引用地址里的内容不能变

------------------------------------------------------------------------------------------------------------------

Final是唯一可以修饰局部变量的修饰符.------------------局部内部类

 

什么时候使用常量:

当在程序中,多个地方使用到共同的数据,而且该数据不会被改变,此时我们专门定义全局的常量.

一般放到一个常量类中

class Contact {public static final int X_SIZE = 100;public static final int Y_SIZE = 100;}

-----------------------------------------------------------------------------------------------------------------

设计模式(Design pattern):是一套反复使用,多人知晓的,进过分类编目地,代码设计经验的总结.

使用设计模式是为了重用代码,让代码更容易被他人理解,保证代码可靠性.毫无疑问,设计模式于人于己都是多赢的

------------------------------------------------------------------------------------------------------------------

单例设计模式(singleton):

目的:保证某一个在整个应用中有且只有一个实例(一个类在内存只存在一个对象),即所有指向该类型实例的引用都指向同一块内存空间

需求:定义一个数组的工具类,使用单例设计模式解决

写单例模式的步骤:单讲饿汉式

 (1)必须在该类中,自己先创建一个对象.

 (2)私有化自身的构造器,防止外界通过构造器创建新的对象

 (3)向外暴露一个公共的静态方法,用于获取自身的对象

class ArrayUtil {//(1)必须在该类中,自己先创建一个对象private static final ArrayUtil instance = new ArrayUtil();//(2)私有化自身构造器,防止外界通过构造器创建新对象private ArrayUtil() {}//(3)向外暴露一个公共的静态方法,用于获取自身的对象public static ArrayUtil getInstance() {return instance;}public void sort(int[] arr) {System.out.println("排序操作");}}
//单例设计模式class SingletonDemo {public static void main(String[] args) {//需要做排序操作ArrayUtil.getInstance().sort(null);}}

-----------------------------------------------------------------------------------------------------------------

工具类:存放了某一类事物的工具方法的类.

工具类存放的包:工具包(util/utils,tools/tool,)存放工具类

工具类起名: xxxUtil/xxxTools

例如: ArrayUtil,StringUtil

 

 

工具类如何设计:工具类在开发中只需要存在一份

(1)如果工具方法没有使用static修饰,说明工具方法得使用工具类的对象来调用

此时把工具类设计为单例的

(2)如果工具方法全部使用static修饰,工具方法只需要使用工具类名调用即可

此时必须把工具类的构造器私有化(防止创建工具类对象调用静态方法)

----------------------------------

一般首选第二种,简单,jdk中提供的工具类都是第二种如java.util.Arrays


 

引出基本类型的包装类

问题1:在面向对象中,”一切皆对象”,现在问题:给一个整数常量int age = 17 ;请问这里age哪里有对象?基本类型,不是对象,此时有矛盾.

问题2 :现在给一个复杂的十进制数据,请迅速转为2进制8 进制, 16进制

问题3:现在使用一种数据类型来表示考试成绩,怎么表示缺考核考试的0

------------------------------------------------------------------------------------------------------------

上述问题,就是因为基本数据类型缺少对象.如果需要对象,必须先有类.

 此时我们可以为每一个基本类型都编写一个对应的包装类,类中包含了该基本类型的一个值.

 

 

装箱及拆箱

 

 

八大基本数据类型的包装类都是用final修饰,都是最终类,都不能被继承.

 

在java的集合框架中,只能存储对象,不能存储基本类型的值.

每次存储到集合中的基本数据都得手动来装箱

 

Sunjava5开始,提供自动装箱和拆箱

 

 

自动装箱和拆箱,也是一个语法糖/编译器级别的新特性

在底层依然是手动装箱和拆箱操作

但是:装箱操作使用的是integer.valueOf的方式

-----------------------------------------------------------------------------------------------------------------

Switch 支持的数据类型:byte,short,char,int也支持对应的包装类

在底层Switch会对包装类做手动拆箱操作

 

解释 Object obj = 17;

(1)先有一个自动装箱操作 int i = 17;

(2)引用类型的自动转换,把子类对象赋给父类对象Object obj = i;

------------------------------------------------------------------------------------------------------------------

Object可以接受一切数据类型的值

 


包装类的常用操作方法

 

1.包装类的常量:

MAX_VALUE/MIN_VALUE/SIZE(在内存中存储多少位)/TYPE(对应的类型)

2.包装类的构造器,xxx类型的包装类xxx

构造器作用:创建包装类

3.基本类型和包装类型的转换(装箱和拆箱)

装箱:

Integer i1 = new Integer(123);

Integer i2 = integer.valueOf(123);//推荐方式,带有缓存

拆箱:

Int a = I1.intValue();

 

xxxValue:表示把当前对象转换为xxx类型

Byte byteValue();

Short shortValue();

 

 

 

4.String和基本类型/包装类型之间的转换操作

String类型转换为包装类

方法1:Static xxx valueOf(String str) string转换为包装类对象

Int i1 = integer.ValueOf(“123”);

方法2: new xxx(String str):

Int i2 = new integer(“123”);

将基本数据类型转为String类型

String str = 17 + “”;

将包装类型转为String类型

String str = 任何对象.toString()

String转为基本数据类型:

parseXxx(String x) : xxx表示八大基本数据类型

String input = “12345”;

Int a = Integer .parseInt(input);

 

 


 

包装类的缓存设计,享元模式flyweight 一种软件设计模式:

Byte short,integer,long:缓存[-128.127]之间的数据;

Character:缓存[0,127]之间的数据

 

 

class CacheDemo {public static void main(String[] args) {Integer i1 = new Integer(123);Integer i2 = new Integer(123);System.out.println(i1 == i2);//falseInteger i3 = Integer.valueOf(123);Integer i4 = Integer.valueOf(123);System.out.println(i3 == i4);//true:在[-1218,127]之间,就获取缓存中的数据Integer i5 = 123;Integer i6 = 123;System.out.println(i5 == i6);//trueInteger i11 = new Integer(255);Integer i21 = new Integer(255);System.out.println(i11 == i21);//falseInteger i31 = Integer.valueOf(255);Integer i41 = Integer.valueOf(255);System.out.println(i31 == i41);//false:不在[-1218,127]之间,就重新new一个Integer i51 = 255;Integer i61 = 255;System.out.println(i51 == i61);//true}}


包装类型对象之间的比较操作:统统使用equals来比较,比较的是包装的数据(Integer类中将equals重写)

特别指出利用equals比较八大包装对象
(如int,float等)和String类(因为该类已重写了equals和hashcode方法)对象时,默认比较的是值,在比较其它自定义对象时都是比较的引用地址。


Integerint的区别

 

(1)默认值:

Int类型是0

Integer默认值为Null

(2)包装类中提供了该类型的很多算法操作方法

Static String toBinaryString(int i): 十进制转换为二进制

Static String toOctalString

(3)在集合框架中,只能存储对象类型,不能存储基本数据类型

(4)Integer int不是相同的数据类型


上述设计的问题:

(1)每个图像都有面积,所有在graph类中定义的求面积方法getArea没问题但是不同的具体求面积的算法是不一样的,也就是说每个图像的子类都必须去覆getAREA方法,如果不覆盖,应该语法报错,必须覆盖

(2)在图像类中定义了getArea方法,该方法不应该存在方法体,因为不同的图像求面积算法不一样,父类不知道该怎么写,所以应该提供方法体方法.

 

-----------------------------------------------------------------------------------------------------------

抽象方法

使用abstract修饰的且没有方法体的方法,称为抽象方法

特点:

(1)使用abstract修饰的且没有方法体的方法

(2)抽象方法修饰符不能是privatefianlstatic

(3)抽象方法需要放在抽象类或者接口中

 

抽象类

abstract修饰的类

特点:

(1)不能创建实例即不能new一个抽象类,即使创建抽象类方法,调用抽象方法没有方法体

(2)可以不包含抽象方法,若一旦包含,该类必须作为抽象类,抽象类可以包含普通方法

(3)若子类没有实现/覆盖父类所有的抽象方法,那么子类也得作为抽象类

(4)构造方法不能都定义为私有的,否则不能有子类(创建子类之前先调用父类的构造方法)

(5)是不完整的,需要作为父类(必须要有子类),功能才得以实现

--------------------------------------------------------------------------------------

抽象类不能实例化

抽象类中可以不存在抽象方法,但是没有太大的意义

--------------------------------------------------------------------------------------

抽象类和普通类的区别

普通类有的常用(方法,字段,构造器),抽象类都有

抽象类不能创建对象,抽象类中可以包含抽象方法


模板方法设计模式:在父类的方法中定义一个总体算法骨架(模板方法),而将一些不足延迟到子类中,因为不同的子类实现细节不同.模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤

---------------------------------------------------------------------------------------------------------

抽象父类赋值定义操作中的业务骨架,而把某些具体的实现步骤延迟到子类中去实现

抽象父类至少提供的方法:

(1)模板方法:一种统一的处理方式,即模板

(2)抽象方法:一种具体的业务功能实现,有子类完成

注意抽象父类提供的模板方法只是定义了一个通用算法,其实现不想依赖子类的辅助


 

原创粉丝点击