Java面向对象学习笔记(四)

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

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二、面对对象---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、小结

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值