面向对象(三)抽象类,接口、内部类、代码块

1、java.lang.Object

1.Object类是所有 java 类的根父类

2.如果在类的声明中未使用 extends 关键字指明其父类,默认类的父类为 java.lang.Object 类。

3.Object类中的功能(属性,方法)具有通用性。

  • 属性:无。
  • 方法:equals() / toString() / getClass()获取当前对象的所属类 / hashCode()/ clone()克隆 / finalize()垃圾回收 / wait() / notify() / notifyAll()

4.Object类只声明了一个空参构造器

面试题:
final、finally、finalize的区别?

1.==和equals()的使用

==:运算符
1.==可以使用在基本数据类型和引用数据类型变量中
2.如果比较的是基本数据类型变量,比较两个变量保存的数据是否相等(不一定类型要相同)。
  如果比较的是引用数据类型变量,比较两个变量的地址值是否相等。即两个引用是否指向同一个对象实体。

equals()方法的使用:
1.equals()是一个方法,不是运算符。
2.只能适用引用数据类型。
3.Object类中equals的定义:
   public boolean equals(Object obj) {
        return (this == obj);
   }
	说明:Object类中定义的equals()==的作用是相同的:比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体

4.像String、Date、File、包装类等都重写了Object类中的equals()方法。
重写以后,比较的不是两个引用地址是否相同,而是比较两个对象的"实体内容"是否相同。

  
练习:
Customer cust1 = new customer("tom",21);
Customer cust2 = new customer("tom",21);
System.out.println(cust1 == cust2);//false

String str1 = new String("atguigu");
String str2 = new String("atguigu");
System.out.println(str1 == str2);//false

System.obj.println(cust1.equals(cust2));//false
System.obj.println(str1.equals(str2));//true

2.equals()方法的重写

通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的"实体内容"是否相同。
那么我们就需要对Object类中的equals()进行重写。

重写的规则:比较两个对象的实体内容是否相同。
//手动实现
public boolean equals(Object obj) {
	if (this == obj){
		return true;
	}
	
	if(obj instanceof Customer){
		Customer cust = (Customer)obj;
		//比较两个对象的每个属性是否相同
//		if(this.age == cust.age && this.name.equals(cust.name)){
//			return true;
//		}else{
//			return false;
//		}

		//或
		return this.age == cust.age && this.name.equals(cust.name);
	}else{
		return false;
	}
}
//自动生成的
右键生成

3.toString()的使用

1.当我们输出一个对象的引用,实际上就是调用当前对象的toString()
2.Object类中对toString()的定义:
	public String toString() {
		return getClass().getName() + "@" + Integer.toHexString(hashCode());
	}
3.向String,Date,File。包装类等都重写了Object的toString方法。
  使得在调用对象的toString方法时,返回实体对象信息。
4.自定义类重写toString方法

2、JUnit单元测试的使用

步骤:
1.选中当前工程 - 右键选择:build path - add libraries - JUnit 4 -下一步
2.创建java类,进行单元测试
	此时的java类要求:①此类是public的 ②此类提供公共的无参的构造器
3.此类中声明的单元测试方法。
	测试的单元测试方法:方法的权限是public ,没有返回值类型,没有形参
4.此单元测试方法上需要声明注解:@Test,并在单元测试类中导入import org.junit.Test;
5.声明好单元测试方法以后就可以在方法体内测试相关代码。
6.写完代码以后,左键双击单元测试方法名,右键:run as - JUnit Test

说明:
1.如果执行没有任何异常:绿条
2.如果执行结果出现异常:红条	

3、包装类

包装类的使用:
1.java提供了中基本数据类型对应的包装类,使得基本数据类型的变量都具有类的特征。

在这里插入图片描述

2.掌握的:基本数据类型、包装类、String三者之间的相互转化

public static void main(String[] args) {
    //基本数据类型 ---> 包装类 :调用包装类的构造器
	Integer int1 = new Integer("123");
	System.out.println(int1.toString());
	
	Float f1= new Float(12.3);
	Float f2= new Float("12.3");
	System.out.println(f1+","+f2);
	
	Boolean b1 = new Boolean(true);
	Boolean b2 = new Boolean("true123");
	System.out.println(b1+","+b2);
	
    //包装类 ---> 基本数据类型 :调用包装类的xxxValue()
	Integer int1 = new Integer(12);
	int i1 = int1.intValue();
	System.out.println(i1 + 1);
	
	/*
	 * JDK 5.0新特性:自动装箱与自动拆箱
	 * 自动装箱:基本数据类型 ---> 包装类
	 * 自动拆箱:包装类 ---> 基本数据类型
	 */
	int num1=10;
    Integer num2=num1;//自动装箱
    
    Integer a=10;
    int b=a;//自动拆箱
    
    //基本数据类型和包装类 ---> String的转换
    int num=10;
	//方式一:连接运算
    String s1=num + "";//int->String
	//方式二:调用String的valueOf(Xxx xxx)
    String s2=String.valueOf(num);//int->String
	
	//String的转换 ---> 基本数据类型和包装类
    String str1 = "123";
  	//调用包装类的parsetXxx(String s);
    int num3=Integer.parseInt(str1);//String->int
  
  	注意:转化时,可能会报NumberFormatException异常
}

面试题

//三目运算符后面两个条件语句对应的类型会在比较前进行统一
//1.
Object o1=true?new Integer(1):new Double(2.0);
System.out.println(o1);//1.0

//2.
Object o2;
if(true){
	o2 =new Integer(1);
}else{
	o2 =new Double(2.0);
}
System.out.println(o2);//1

//3.
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j);//false

//Integer内部定义了IntegerCache结构,IntegerCache中定义了Integer[],
//保存了从-128到+127范围的整数。如果我们使用自动装箱的方式,
//给Integer赋值的范围在-128到+127范围内时,可以直接使用数组中元素,不用再去new了。

Integer m = 1;
Integer n = 1;
System.out.println(m == n);//true

Integer x = 128;
Integer y = 128;
System.out.println(x == y);//false

4、static关键字的使用

1.static:静态的
2.static可以用来修饰属性、方法、代码块、内部类
3.使用static修饰属性:静态变量(类变量)
	3.1 属性:按是否使用static修饰,又分为:静态属性(静态变量) VS 非静态属性(实例变量)
	实例变量:我们创建了类的多个对象,每个对象都的拥有一套类中的非静态属性。当修改其中一个对象的
			 非静态属性时,不会到时其他对象中同样的属性值的修改。
	静态变量:我们创建了类的多个对象,多个对象共享用一个静态变量。当通过某一个对象修改静态变量时,
			  会导致其他对象调用此静态变量时,是修改过的。
	3.2 static修饰属性的其他说明:
		①静态变量随着类的加载而加载。可以通过"类.静态变量"的方式进行调用。
		②静态变量的加载早于对象的创建。
		③由于类只会加载一次,则静态变量在内存中也只存在一份,存在方法区的静态域中。
		④		类变量		实例变量
		类		 yes		no
		对象		yes		   yes
		
	3.3 静态属性举例:System.out;Math.PI;
		
4.使用static修饰方法:静态方法
	①随着类的加载而加载,可以通过"类.静态方法"的方式进行调用。
	②     		静态方法 	非静态方法
		类		yes			no
		对象		yes			yes
	③静态方法中,只能调用静态的方法或属性
	 非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性。

5.static注意点:
	①在静态的方法内,不能使用this关键字、super关键字
	②关于静态属性和静态方法的使用,都从生命周期的角度去解决。

6.开发中如何确定一个属性要声明为static> 属性被多个对象所共享的,不会随着对象的不同而不同的。
	> 类中的常量也常常声明static

  开发中如何确定一个方法要声明为static> 操作静态属性的方法,通常设置为static> 工具类中的方法,习惯上声明为static

5、设计模式

1.1理解
设计模式是在大量的实践中总结和理论化之后优的代码结构、编程风格、以及解决问题的思考方式。

1.2常用设计模式--- 23种经典的设计模式
创建型模式,共5, 工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共种:适配器模式、装饰器横式、代理模式、外观模式、桥接模式、组合横式、享元横式。
行为型模式,共11: 策略模式、模板方法模式、观察者横式、迭代器模式、责任链模式、命令模式、备忘录模式、状态横式、访问者模式、中介者模式、解释器模式。

单例设计模式

1.所谓类的单利设计模式,就是采取一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例。
2.如何实现?
	饿汉式 VS 懒汉式
3.饿汉式和懒汉式的区别
	饿汉式:坏处,对象加载时间过长。
			好处,线程安全的。
	懒汉式:好处,延迟对象的创建。
			坏处,线程不安全的。

4.应用场景:
网站计数器,应用程序的日志应用,数据库连接池,Application。
		
代码:		
public class SingletonTest{
	public static void main(String[] args){
		Bank bank1 = Bank.getInstance();
		Bank bank2 = Bank.getInstance();
		System.out.println(bank1 == bank2);//true
	}
}

//饿汉式
class Bank{
	//1.私有化类的构造器
	private Bank(){
	
	}
	//2.内部创建类的对象
	private static Bank instance = new Bank();
	//3.提供公共的静态的方法,返回类的对象
	public static Bank getInstance(){
		return instance;
	}
}

//懒汉式
class Bank{
	//1.私有化类的构造器
	private Bank(){
	
	}
	//2.声明当前类的对象,没有初始化
	private static Bank instance = null;
	//3.声明public static的返回当前类对象的方法
	public static Bank getInstance(){
		if(instance == null){
            instance=new Bank();
        }
		return instance;
	}
}


main()方法的使用说明:
1.main()方法作为程序的入口
2.main()也是一个普通的静态方法
3.main()方法可以作为我们与控制台交互的方式(之前:使用Scanner)

模板方法的设计模式

1.解决的问题
在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。
但是某些部分易变,易变部分可以抽象出来,供不同子类实现。这就是一种模板模式。

2.举例
abstract class Template{
	//计算某段代码执行所需要花费的时间
	public void spendTime(){
		long start = System. currentTimeMillis();
		this.code();//不确定的部分、易变的部分
		1ong end = System. currentTimeMillis();
		System.out.println("花费的时间为:+ (end - start));
	}
	public abstract void code();
}

class SubTemplate extends Template{
	@Override
	public void code() {
		for(int i = 2;i <= 1000;1++){
			boolean isFlag = true;
			for(int j = 2;j <= Math.sqrt(i);j++){
				if(i%j==0){
					isFlag = false;
					break;
				}
			}
			if(isFlag){
				System.out.println(i);
			}
		}
	}
}

3.应用场景
模板方法设计模式是编程中经常用得到的模式。各个框架、类库中都有他的影子,比如常见的有:
数据库访问的封装
Junit单元测试
JavaWeb的Servlet中关于doGet/doPost方法调用
Hibernate中模板程序
Spring中JDBCTemlate、HibernateTemplate等

6、类的成员之四:代码块

1.代码块(初始化块)作用:用来初始化类、对象。

2.代码块如果有修饰的话,只能使用static。

3.分类:静态代码块 VS 非静态代码块

非静态能调用静态的属性方法,静态的不能掉用非静态的属性方法。

4.静态代码块

  • 内部可以有输出语句
  • 随着类的加载而执行,只执行一次
  • 作用:初始化类的信息
  • 如果一个类中定义了多个静态代码块,则按声明的先后顺序执行
  • 静态代码块的执行要优先于非静态代码块的执行
  • 静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构

5.非静态代码块

  • 内部可以有输出语句
  • 随着对象的创建而执行
  • 每创建一个对象,就会执行一次非静态代码块。
  • 作用:可以在创建对象时,对对象的属性等进行初始化
  • 如果一个类中定义了多个非静态代码块,则按声明的先后顺序执行
  • 非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法

对属性可以赋值的位置

对属性可以赋值的位置:
1)默认初始化
2)显示初始化
3)构造器初始化
4)有了对象以后,可以通过"对象.属性"或"对象.方法"的方式进行赋值
5)在代码块中赋值

执行的先后顺序:1 - 2 / 5 - 3 - 4
总结:由父及子,静态先走

7、final关键字的使用

final:最终的
1.final可以用来修饰的结构:类、方法、变量
2.final用来修饰一个类:此类不能被其他类所继承。
	比如:String类,System类,StringBuffer类
	
3.final用来修饰方法:表明此方法不能被重写。
	比如:Object类中的getClass();

4.final用来修饰变量
此时的变量就称为常量。
	4.1 final修饰属性:
		可以考虑赋值的位置有:显式初始化、代码块中初始化、构造器中初始化。
	4.2 修饰局部变量
        尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。

static final:用来修饰属性:全局常量

8、抽象类与抽象方法

abstract关键字的使用
1.abstract抽象的
2.abstract可以用来修饰的结构:类、方法
3.abstract修饰类:抽象类
	> 此类不能实例化
	> 抽象类中一定有构造器,便于子类实例化时调用。
	> 开发中,都会提供抽象类的子类,让子类对象实例化,完成相关操作。
	
4.abstract修饰方法:抽象方法
public abstract void test();
	> 抽象方法只有方法的声明,没有方法体。
	> 包含抽象方法的类一定是抽象类;反之,抽象类中可以没有抽象方法的。
	> 若子类重写了父类类中的所有的抽象方法后,此子类方可实例化。
	  若子类没有重写了父类类中的所有的抽象方法,则子类也是一个抽象类,需要使用abstract修饰。

5.注意
1abstract不能用来修饰:属性,构造器等结构。
2abstract不能用来修饰私有方法、静态方法、final方法、final的类。

创建匿名子类的匿名对象
method1(new Person(){
	@Override
	public void eat(){
		System.out.println("吃好吃的")
	}
	@Override
	public void breath(){
		System.out.println("好好呼吸空气")
	}
});

9、接口(interface)

1.接口的使用interface来定义
2.Java中,接口和类是并列的两个结构。
3.如何定义接口,定义接口的成员
	3.1 jdk7以前:只能定义全局常量和抽象方法
		> 全局常量:public static final的。但是书写时,可以省略不写
		> 抽象方法:public abstract的。但是书写时,可以省略不写
	3.2 jdk8:除了定义全局常量和抽象方法外,还可以定义静态方法、默认方法。

4.接口中不能定义构造器,意味着接口不能实例化。
5.Java中,接口通过让类去实现(implements)的方式来使用。
	如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化
	如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类
6.Java类中可以实现多个接口。
	格式:class AA extends BB implements CC,DD{}
7.接口与接口之间可以继承,也可以多继承
8.接口的具体使用,体现多态性。
9.接口实际上可以看做是一种规范。
10.开发中体现了面向接口的编程。


Java8中关于接口的新规范
//知识点1:接口中定义的静态方法,只能通过接口来调用。
//知识点2:通过实现类的对象,可以调用接口中的默认方法。
//如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法
//知识点3:如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的默认方法,那么子类在没重
写此方法的情况下,默认调用的是父类中的同名同参数的方法。-->类优先原则 
//知识点4:如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,
//那么在实现类没重写此方法的情况下,报错。-->接 口冲突。
//这就需要我们必须在实现类中重写此方法
//知识点5:如何在子类(或实现类)的方法中调用父类、 接口中被重写的方法
public void myMethod(){
	method3();//调用自己定义的重写的方法
	super.method3();//调用的是父类中声明的
	//调用接口中的默认方法
	CompareA.super.method3();
	CompareB.super.method3();
}

面试题:抽象类与接口的异同

相同点:
不能实例化;都可以包含抽象方法的。

不同点:
抽象类:通过extends来继承,只能继承一个抽象类(单继承),
	   抽象类中一定有构造方法,创建子类对象时被调用。
	   抽象类中不光有抽象方法,还可以有其他方法。
接口:接口通过implements来实现,允许实现多个接口(多继承),
	 接口中不存在构造方法,
	 jdk7及以前接口中只能声明全局常量和抽象方法,
	 jdk8以后还可以定义静态方法和默认方法,
	 jdk9以后还可以定义私有方法。 

接口的应用:代理模式

1.解决的问题:
	代理模式是Java开发中使用较多的一种设计模式。代理设计就是为其他对象提供一种代理以控制对这个对象的访问。
2.应用场景:
	安全代理、远程代理、延迟加载
分类:
	静态代理、动态代理
3.代码:
/**
 * 代理模式:将两者都要实现的行为封装在接口中,被代理对象和代理对象都继承该接口
 * 代理对象中声明被代理对象属性,并创建拥该属性的构造器,通过创建代理对象完成
 * 被代理对象的方法。
 */
class NetWorkTest{
    public static void main(String[] args) {
        Server server = new Server();
		ProxyServer proxyServer = new ProxyServer(server);
		proxyServer.browse();
}

interface NetWork {
    public void browse();
}

//被代理类
public class Server implements NetWork {
	@Override
	public void browse(){
		System.out.println("真实的服务器访问网络");
	}
}

//代理类
public class ProxyServer implements NetWork{
	
	private NetWork work;
	
	public ProxyServer(NetWork work){
		this.work = work;
	}
	
	public void check(){
		System.out.println("网络之前的检查工作");
	}
	
	@Override
	public void browse(){
		check();
		work.browse();
	}
}

10、类的成员之五:内部类

1.Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类。

2.内部类的分类:成员内部类(静态,非静态)VS 局部内部类(方法内,代码块内,构造器内)

3.成员内部类:
	一方面,作为外部类的成员:
		> 调用外部类的结构
		> 可以被static修饰
		> 可以被4种不同的权限修饰
	
	另外一方面,作为一个类:
		> 类内可以定义属性、方法、构造器等
		> 可以被final修饰,表示此类不能被继承。言外之意,不适用final,可以被继承。
		> 可以被abstract修饰
		
4.关注如下的3个问题
	4.1 如何实例化成员内部类的对象
	4.2 如何在成员内部类中区分调用外部类的结构
	4.3 开发中局部内部类的使用

public class TnnerClassTest{
	public static void main(String[] args) {
		//创建Dog实例(静态的成员内部类)
		Person.Dog dog = new Person.Dog();
		dog.show();
		//创建Bird实例(非静态的成员内部类)
		Person p = new Person();
		Person.Bird bird = p.new Bird();
		bird.sing();
		
		System.out.println();
		bird.display("黄鹂");
		
		System.out.println();
	}
}	

class Person{
	
	String name = "小明";
	int age;
	
	public void eat(){
			System.out.println("人吃饭");
		}

	//静态成员内部类
	static class Dog{
		String name = "鸟";
		int age;
		public void show(){
			System.out.println("卡拉是条狗");
//			eat();
		}
	}
	
	//非静态成员内部类
	final class Bird{
		String name = "杜鹃";
		public Bird{
		
		}
		public void sing(){
			System.out.println("我是一只小鸟");
			Person.this.eat();//调用外部的非静态属性
			//eat();
		}
		public void display(String name){
			System.out.println(name);//方法的形参
			System.out.println(this.name);//内部类的属性
			System.out.println(Person.this.name);//外部类的属性
		}
	}
	
	public void method(){
		//局部内部类
		class AA{
		
		}
	}
		
	{
		//局部内部类
		class BB{
		
		}
	}
	
	public Person(){
		//局部内部类
		class CC{
		
		}
	}
	
	//返回一个实现了Comparable接口的类的对象
	public Comparable getComparable(){
	
		//创建一个实现了Comparable接口的类:局部内部类
		//方式一:
		class MyComparable implements Comparable{
		
			@Override
			public int compareTo(Object o){
				return 0;
			}
		}
		return new myComparable();
		
		
		//方式二:
		return new Comparable(){
			@Override
			public int compareTo(Object o){
				return 0;
			}
		};
		
	}
}	

注意点:
在局部内部类的方法中(比如: show)如果调用局部内部类所声明的方法(比如: method)中的局部变量(比如:num)的话,要求此局部变量声明为final的。

jdk 7及之前版本:要求此局部变量显式的声明为final的
jdk 8及以后的版本:可以省略final的声明

5.总结:	
成员内部类和局部内部类,在编译以后,都会生成字节码文件
格式:成员内部类:外部类$内部类名.class
	 局部内部类:外部类$数字 内部类.class
面试题:创建静态内部类对象和非静态内部类对象:
//静态内部类对象
Person.Dog dog=new Person.Dog();
//非静态内部类对象
Person p=new Person();
Person.Bird bird=new p.bird();

如果有收获!!! 希望老铁们来个三连,点赞、收藏、转发。
创作不易,别忘点个赞,可以让更多的人看到这篇文章,顺便鼓励我写出更好的博客

猜你喜欢

转载自blog.csdn.net/weixin_45606067/article/details/108258152
今日推荐