二、面对对象---4.
(一)代码块
159、字段不存在多态特征
class SuperClass
{
public String name = "Super.name";
public void doWork()
{
System.out.println("Super.doWork");
}
}
class SubClass extends SuperClass
{
public String name = "Sub.name";
public void doWork()
{
System.out.println("Sub.doWork");
}
}
//字段不存在多态特征
class FieldDemo
{
public static void main(String[] args)
{
SuperClass clz = new SubClass();
clz.doWork(); //Sub.doWork
System.out.println(clz.name); //??? Super.name
}
}
通过对象调用字段,在编译时期就已经决定了调用哪一块内存空间的数据。
字段不存在覆盖的概念,在多态时,不能有多态特征(在运行时期体现子类特征)。只有方法才有覆盖的概念。
当子类和父类存在相同的字段的时候,无论修饰符是什么(即使是private),都会在各自的内存空间中存储数据。

160.代码块语句

1)局部代码块:直接定义在方法内部的代码块
//代码块
class CodeBlockDemo
{
public static void main(String[] args)
{
{
//局部代码块
int age = 17;
System.out.println(age);
}
System.out.println(age); // 错误: 找不到符号
}
}
一般是不会直接使用代码块的,只不过我们会结合if,while,for,try等关键字联合,表示一块代码区域
if (true)
{
System.out.println("局部代码块");
}
2)初始化代码块(构造代码块):直接定义在类中。每次创建对象都会调用构造器,在调用构造器之前会先执行本类中的初始化代码块。
//代码块
class CodeBlockDemo
{
{
System.out.println("初始化代码块");
}
CodeBlockDemo()
{
System.out.println("构造器....");
}
public static void main(String[] args)
{
System.out.println("进入main方法");
//创建三个CodeBlockDemo对象
new CodeBlockDemo();
new CodeBlockDemo();
new CodeBlockDemo();
}
}
通过反编译发现,初始化代码块也作为构造器的最初的语句

一般不使用初始化代码块,即使要做初始化,一般也在构造器中做即可,如果初始化代码块比较多,此时构造器的结构比较混乱,此时专门定义一个方法做初始化操作,再在构造器中调用即可
3)静态代码块:使用static修饰的初始化代码块。特点:在主方法执行之前执行静态代码块,而且只执行一次。main方法是程序入口,为什么静态代码块优先于main方法执行。静态成员随着字节码的加载也加载进JVM,此时main方法还未执行,因为方法需要JVM调用,先把字节码加载进JVM,而后JVM再调用main方法。一般用来做初始化操作,加载资源,加载配置文件等。
成员+static:属于类
成员不加static:属于对象

//不写主方法,打印Hello World!
class CodeBlockDemo1
{
static
{
System.out.println("Hello World!");
}
public static void main(String[] args)
{
}
}
161、面试题-代码执行顺序
//面试题,分析下面代码的运行顺序
/*输出结果:
1)1 :App类依赖于SubClass类,所以得先把SubClass类的字节码加载进JVM
2)构造SuperClass :
3)2
4)4
5)3
6)Hello
*/
public class App
{
private static App d = new App(); //static字段的初始化,静态的成员在底层通过静态代码块做初始化,相当于private static App d = null;
private SubClass t = new SubClass(); //非static字段的初始化都在当前类的构造器前面执行,非静态成员在底层是通过构造器做初始化,private SubClass t = null;
static
{
//d = new App();
System.out.println(3);
}
public App()
{
//t =new SubClass();
System.out.println(4);
}
public static void main(String[] args)
{
System.out.println("Hello");
}
}
//父类
class SuperClass
{
SuperClass()
{
System.out.println("构造SuperClass");
}
}
//子类
class SubClass extends SuperClass
{
static //静态代码块
{
System.out.println(1);
}
public SubClass() //子类构造器,先调用父类构造器,在执行子类构造器内容
{
//super(); //表示调用父类无参数构造器
System.out.println(2);
}
}
(二)final修饰符
162、final类和final方法
final class SuperClass
{
{
}
}
class SubClass extends SuperClass //错误: 无法从最终SuperClass进行继承
{
}
//final修饰符
class FinalDemo
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}
class SuperClass
{
public final void doWork(){}
}
class SubClass extends SuperClass
{
public final void doWork(){} // 错误: SubClass中的doWork()无法覆盖SuperClass中的doWork()
}
//final修饰符
class FinalDemo
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}
163.final变量(常量)

class SuperClass
{
public final void doWork(){}
}
class SubClass extends SuperClass
{
}
class Person
{
public String info = "最初的值";
}
//final修饰符
class FinalDemo
{
//final static String name; //错误: 变量 name 未在默认构造器中初始化
final static String name = "AAA";
public static void main(String[] args)
{
//name = "BBB"; //错误: 无法为最终变量name分配值
final Person p = new Person();
System.out.println(p.info); //最初的值
p.info = "XXX";
System.out.println(p.info); //XXX
//p = new Person(); //错误: 无法为最终变量p分配值
}
}
//常量类
class Consts
{
public static final int X_SIZE = 100;
public static final int Y_SIZE = 100;
}
164、单例设计模式
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 SingletionDemo
{
public static void main(String[] args)
{
//需要做排序:不同类中
ArrayUtil.getInstance().sort(null);
//需要做排序
ArrayUtil.getInstance().sort(null);
//需要做排序
ArrayUtil.getInstance().sort(null);
//需要做排序
ArrayUtil.getInstance().sort(null);
}
}
165、工具类的设计
(三)基本类型包装类
166、引出基本类型包装类

167、装箱和拆箱操作
//包装int类型的值
public class IntWapper
{
private int value; //值
public IntWapper(int value)
{
this.value = value;
}
//包含int类型相关的算法:把10进制转换成2进制/8进制/16进制
}
class Xxxx
{
public static void main(String[] args)
{
IntWapper wapper =null; //没有对象,没有数据
IntWapper wapper = new IntWapper(0); //有对象,有数据,数据为0
}
}

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


在Java的集合框架中,只能存储对象,不能存储基本类型的值,每次存储到集合中的基本数据都得手动来装箱,从Java5开始Sun公司提供了自动装箱和拆箱。但是:装箱操作使用的是Integer.valueOf的方式,而不是new Integer。
switch支持的数据类型:byte,short,char,int,也支持对应的包装类。为何?就是在底层,switch中会对包装类做手动拆箱操作
//演示包装类:装箱和拆箱操作
class IntegerDemo
{
public static void main(String[] args)
{
//装箱操作:把一个基本类型的值,转换为对应包装类对象
Integer num1 = new Integer(17); //方式1
Integer num2 = Integer.valueOf(18); //方式2
//拆箱操作:把包装类的对象装换为对应的基本类型变量
int num3 = num1.intValue();
System.out.println(num1); //17
System.out.println(num2); //18
System.out.println(num3); //17
//自动装箱:可以直接把一个基本数据类型值赋给对应的包装类对象
Integer num4 = 19;
//自动拆箱:直接把一个包装类对象赋给对应的基本类型变量
int num5 = num4;
System.out.println(num4); //19
System.out.println(num5); //19
Integer num = 10;
switch(num)
{
case 1; break;
case 2; break;
}
Object obj = 17; //1)自动装箱:Integer i =17; 2)引用的自动类型转换,把子类对象赋给父类变量:Object obj = i;
//Object可以接收一切类型的值。Object数组:Object[],该数组可以装一切数据类型
Object[] arr = {"A",12,3.24,true};
}
}
168、包装类的常用操作
/*2)包装类的构造器:xxx类型的包装类Xxx(xxx表示8大基本数据类型)
Xxx(xxx value):接收自己的基本类型值,如 Integer(int val)
Xxx(String value):但是Character除外
构造器的作用:创建包装类对象
*/
class WapperDemo
{
public static void main(String[] args)
{
//1)包装类的常量:MAX_VALUE、MIN_VALUE、SIZE(在内存中存储占多少位)、TYPE(对应的基本类型)
System.out.println(Integer.MAX_VALUE); //2147483647
System.out.println(Integer.MIN_VALUE); //-2147483648
System.out.println(Integer.SIZE); //32
System.out.println(Double.SIZE); //64
System.out.println(Integer.TYPE); //int
Long num = 123L; //自动装箱
int i = num.intValue(); //Long---->int
byte b = num.byteValue(); //Long---->byte
Integer i1 = Integer.valueOf("123"); //把String装换为包装类Integer类型
Integer i2 = new Integer("123");
System.out.println(new Boolean("true")); //true
System.out.println(new Boolean("SB")); //false
}
}
/*
3)基本类型和包装类型的转换(装箱和拆箱)
装箱:
Integer i1 = new Integer(123);
Integer i1 = Integer.valueOf(123); //推荐,带有缓存
拆箱:
int val = i1.intValue();
4)String和基本类型/包装类型之间的转换操作
String和int/Integer之间的转换操作:转换方法必须在String类中或Integer类中
把String装换为包装类Integer类型
static Xxx valueOf(String str); //把String转换为包装类对象
new Xxx(String str);
把基本数据类型转换为String:
String str = 17 + "";
把包装类对象转换成String
String str = 任何对象.toString();
把String转换成基本数据类型
static xxx parseXxx(String s);
String input = "123";
int num = Integer.parseInt(input);
5.Boolean b = new Boolean("SB"); //false 只认可true/TRUE,为true,其他的都是false
*/


169、包装类中的缓存设计
包装类中的缓存设计(享元模式)
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); //每次new都会开辟新的内存空间,新的地址
System.out.println(i1 == i2); //false ==比较的是内存地址
Integer i3 = Integer.valueOf(123);
Integer i4 = Integer.valueOf(123);
System.out.println(i3 == i4); //ture : [-128,127),在这个范围就获取缓存中的数据,并没有去开辟新的内存空间
Integer i5 = 123; //自动装箱,底层:Integer.valueOf(123);
Integer i6 = 123;
System.out.println(i5 == i6); //ture
System.out.println("----------------");
Integer i11 = new Integer(250);
Integer i21 = new Integer(250);
System.out.println(i11 == i21); //false
Integer i31 = Integer.valueOf(128); //250不在[-128,127]之间,就得new Integer()
Integer i41 = Integer.valueOf(128);
System.out.println(i31 == i41); //false
Integer i51 = 250;
Integer i61 = 250;
System.out.println(i51 == i61); //false
}
}

包装类型对象之间的比较操作,使用equals方法来做比较,比较的是包装的数据
170、Integer与int的区别
Integer与int的区别(包装类型和基本数据类型的区别)
1)默认值:int的默认值是0;Integer的默认值是null。推论:Integer即可表示null,又可以表示0
2)包装类中提供了该类型相关的很多算法操作方法
class IntegerDemo1
{
public static void main(String[] args)
{
Integer num = null;
num = 0;
System.out.println(Integer.toBinaryString(1024)); //10000000000 把十进制转换成二进制
System.out.println(Integer.toOctalString(1024)); //2000 把十进制转换成八进制
System.out.println(Integer.toHexString(1024)); //400 把十进制转换成十六进制
}
}
3)在集合框架中,只能存储对象类型,不能存储基本数据类型值
4)Integer和int不是相同的数据类型
class IntegerDemo1
{
public static void main(String[] args) {}
public void ooxx(int val){}
//public void ooxx(int val){} // 方法重载 错误: 已在类 IntegerDemo1中定义了方法 ooxx(int)
public void ooxx(Integer val){}
}
5)方法中的基本数据类型变量主要存储在栈中,包装类型存放于堆中
开发中建议使用包装类型
171、引出抽象方法设计

class Gragh
{
public Double getArea()
{
return 0.0;
}
}
//圆
class Circle extends Gragh
{
private Integer r;
Circle(Integer r)
{
this.r = r;
}
//求面积
public Double getArea()
{
return 3.14*r*r;
}
}
//矩形
class Rectangle extends Gragh
{
private Integer width; //长
private Integer height; //高
Rectangle(Integer width, Integer height)
{
this.width = width;
this.height = height;
}
//求面积
public Double getArea()
{
return width * height.doubleValue();
}
}
//三角形
class Triangle extends Gragh
{
private Integer a;
private Integer b;
private Integer c;
Triangle(Integer a, Integer b, Integer c)
{
this.a = a;
this.b = b;
this.c = c;
}
}
//圆(circle)、矩形(rectangle)、三角形(triangle)的面积
class GraphDemo
{
public static void main(String[] args)
{
System.out.println(new Circle(10).getArea()); //314.0 创建一个圆对象,再用圆对象调用求面积的方法
System.out.println(new Rectangle(10,10).getArea()); //100.0
System.out.println(new Triangle(3,4,5).getArea()); //0.0
}
}

172、抽象方法和抽象类
abstract class Gragh //抽象类
{
abstract public Double getArea(); //抽象方法
}
//圆
class Circle extends Gragh
{
private Integer r;
Circle(Integer r)
{
this.r = r;
}
//求面积
public Double getArea()
{
return 3.14*r*r;
}
}
//矩形
class Rectangle extends Gragh
{
private Integer width; //长
private Integer height; //高
Rectangle(Integer width, Integer height)
{
this.width = width;
this.height = height;
}
//求面积
public Double getArea()
{
return width * height.doubleValue();
}
}
//三角形
class Triangle extends Gragh
{
private Integer a;
private Integer b;
private Integer c;
Triangle(Integer a, Integer b, Integer c)
{
this.a = a;
this.b = b;
this.c = c;
}
public Double getArea()
{
Double p = (a + b + c)/2.0;
return Math.sqrt(p *(p -a)*(p -b)*(p -c));
}
}
//圆(circle)、矩形(rectangle)、三角形(triangle)的面积
class GraphDemo
{
public static void main(String[] args)
{
System.out.println(new Circle(10).getArea()); //314.0 创建一个圆对象,再用圆对象调用求面积的方法
System.out.println(new Rectangle(10,10).getArea()); //100.0
System.out.println(new Triangle(3,4,5).getArea()); //0.0
}
}

普通类有的成员/方法/字段/构造器,抽象类都有;抽象类不能创建对象,抽象类中可以包含抽象方法
173、引出模板方法设计模式
需求:统计不同操作的耗时时间
//String的连接10000次
class StringOperate
{
public long doWork()
{
long begin = System.currentTimeMillis(); //当前时间
String str = "";
for (int i=0; i<10000 ;i++ )
{
str +=i;
}
long end = System.currentTimeMillis(); //当前时间
long time = end - begin; //时间差
return time;
}
}
//int相加10000次
class IntOperate
{
public long doWork()
{
long begin = System.currentTimeMillis(); //当前时间
long sum = 0;
for (int i=0; i<10000 ;i++ )
{
sum +=i;
}
long end = System.currentTimeMillis(); //当前时间
long time = end - begin; //时间差
return time;
}
}
//模板方法设计模式
class TemplateMethodDemo
{
public static void main(String[] args)
{
//统计String连接10000次和int相加10000次的时间差
long time = new StringOperate().doWork();
System.out.println(time); //472
long time1 = new IntOperate().doWork();
System.out.println(time1); //1
}
}


174、分析模板方法设计模式

![]()
//操作模板类
abstract class AbstractOperateTimeTemplate
{
//模板方法:总体算法的骨架,子类不能修改
final public long getTotalTime()
{
long begin = System.currentTimeMillis(); //当前时间
//具体操作(留给子类完成)
this.doWork();
long end = System.currentTimeMillis(); //当前时间
long time = end - begin; //时间差
return time;
}
//定义一个抽象方法,具体操作必须子类覆盖
protected abstract void doWork();
}
//String的连接10000次
class StringOperate extends AbstractOperateTimeTemplate
{
protected void doWork()
{
String str = "";
for (int i=0; i<10000 ;i++ )
{
str +=i;
}
}
}
//int相加10000次
class IntOperate extends AbstractOperateTimeTemplate
{
protected void doWork()
{
int sum = 0;
for (int i=0; i<10000 ;i++ )
{
sum +=i;
}
}
}
//模板方法设计模式
class TemplateMethodDemo1
{
public static void main(String[] args)
{
//统计String连接10000次和int相加10000次的时间差
System.out.println(new StringOperate().getTotalTime()); //472
System.out.println(new IntOperate().getTotalTime()); //1
}
}

《JAVA设计模式》之模板模式(Template):https://www.cnblogs.com/betterboyz/p/9377881.html
175、小结

本文详细介绍了Java中面向对象的几个关键概念:包括代码块的分类及其执行顺序,final修饰符在类、方法和变量上的应用,单例设计模式,以及基本类型包装类的特性,如装箱拆箱、缓存设计和与原始类型int的区别。此外,还涉及了抽象方法和模板方法设计模式的理解。



510

被折叠的 条评论
为什么被折叠?



