java面向对象下

Java面向对象(下)

继承

java三大特性之一 继承 在逻辑上具有 is-a 关系的类 可以声明成继承关系

继承好处:代码的复用性 扩展性

使用关键字 extends 来表示当前父类是谁

在Java中只有单一继承 :

一个子类只能有一个父类 而一个父类 可以派生出多个子类

但继承关系可以向下传递 父 —> 儿 -->孙 -->…–>n

class Employee {
	private String name; //姓名
	private double salary = 2000.0; //薪水
	public Employee(String name, double salary){
	this.name = name;
	this.salary = salary;
}
public Employee(){}
	public double getSalary(){ return salary; }
}
class Manager extends Employee{
	private double bonus; //奖金
	public void setBonus(double bonus){ this.bonus = bonus; }
}
	public class InheritanceTest {
		public static void main(String [] args){
	Manager manager = new Manager();
	manager.getSalary();
}
}

父类中除了构造器之外其他的所有信息都能被子类继承

子类在继承父类的信息后 可以在原有基础上进行扩展 扩展的内容只能子类自己使用 父类无法访问

在创建子类的过程中 一定会先创建父类 如果没有显示声明 则会默认掉用父类的无参构造来进行创建

如果父类没有无参构造 则必须手动显示声明调用父类的已有构造器

super

在Java中 除了this关键字 之外 还有一个super关键字

super 只能出现在继承关系的子类中 表示某个参数或者某个方法 是父类的属性或方法

super关键字 在一般情况下可写可不写 一般不写

在以下两种情况下 必须要声明super关键字

  • 子类方法 重写父类方法的同时 还希望调用父类原有方法体内容 此时必须用super关键字来声明哪 个是父类方法 否则会出现无出口递归 造成栈溢出异常
class Employee {public void displayInfo(){ System.out.println(“name=+ name); }
}
	class Manager extends Employee{
	private double bonus; //奖金
	private String position; //职位
	public Manager(String name, double salary, String position){
	super(name, salary);
	this.position = position;
	super.displayInfo();
}
public void setBonus(double bonus){ this.bonus = bonus; }
}
  • 在父类只有有参构造时 子类必须使用super关键字 并在当前构造器的第一行进行 父类构造的调用
class Employee {
	private String name; //姓名
	private double salary = 2000.0; //薪水
	public Employee(String name, double salary){
	this.name = name;
	this.salary = salary;
}
public Employee(){}
	public double getSalary(){ return salary; }
	public void displayInfo(){ System.out.println(“name=+ name); }
}
class Manager extends Employee{
	private double bonus; //奖金
	private String position; //职位
	public Manager(String name, double salary, String position){
	super(name, salary);
	this.position = position;
}
	public void setBonus(double bonus){ this.bonus = bonus; }
}

访问修饰符

所有的类、属性、方法都是有使用范围的 由访问修饰符类决定

ava中有4大访问修饰符:

位置private默认protectedpublic
同一个类
同一个包内的类
不同包内的子类
不同包并且不是子类

方法的重写

当子类不满足父类提供的方法时 需要重写父类方法 该过程叫做方法的重写 override

在重写中 Java专门定义了一个注解 @Override 用来在编译过程中校验当前方法是否构成重写

构成重写的语法条件

  1. 发生在继承关系中
  2. 方法名相同
  3. 参数列表相同
  4. 返回值类型兼容
  5. 访问范围不能被缩小
  6. 异常范围不能被扩大

注意:静态方法只能重写父类的静态方法。

class Employee {
	private String name; //姓名
	private double salary = 2000.0; //薪水
	public Employee(String name, double salary){
	this.name = name;
	this.salary = salary;
}
	public double getSalary(){ return salary; }
}
class Manager extends Employee{
	private double bonus; //奖金
	private String position; //职位
	public Manager(String name, double salary, String position){
	super(name, salary);
	this.position = position;
}
	public void setBonus(double bonus){ this.bonus = bonus; }
	public double getSalary(){
	return super.getSalary() + bonus;
}
}

static关键字

对于希望数据共享的属性或方法 可以使用static关键字进行修饰 其内容会随着类的加载而初始化 整个 程序只有一份static数据

static既可以修饰属性 该属性可被共享

static也可修饰方法 该方法只能调用static修饰的成员 而不能调用非static修饰的内容

static修饰的内容 可以称之为类下属的属性和方法

两种调用方式: 通过类名直接调用 (建议) 通过实例名进行调用(不建议)

对于static修饰的属性 提供了静态代码块 可以进行静态属性初始化

public class Dog{
	private static int count = 100;
	private int id;
	private String name;
	public Dog(String name){
	this.name = name;
	id = count++;
}
	public void displayInfo(){
	System.out.print(“名字是:+ name + 编号是" + id);
}
	public static void currentCount(){
	System.out.println("当前编号是" + count);
}
	public static void main(String[] args){
	Dog.currentCount();
	Dog dog = new Dog("小黑");
	dog.displayInfo();
	Dog dog2 = new Dog(“旺财”);
	dog2.displayInfo();
	Dog.currentCount();
}
}

static 修饰的方法中 不能使用this和super关键字

static代码块 每次类加载时 只执行一次 而普通代码块 随着对象的创建 每次都会执行

执行顺序:

​ 静态代码块 --> 普通代码块 -->构造方法

​ --> 普通代码块 --> 构造方法 …

public class Student{
	private static String country;
	private String name;
static {
	country = "中国";
	System.out.println("Student类已经加载");
}
	public Student(String name){
	this.name = name;
}
	public void displayInfo(){
	System.out.println("我的名字是:" + name + ",国家是:" + country);
}
	public static void main(String[] args){
//Student stu = new Student("张三");
//stu.displayInfo();
}
}

final关键字

final修饰的变量(成员变量或局部变量)的值不能改变,即等同于常量,在定义时就必须要进行初始化, 之后就再也不改变它的值了。在后期版本中可以将声明和初始化分开执行 但是每个步骤都不能省略 且 一旦赋值完成后 值不能修改

final修饰方法的参数叫最终参数。调用这个方法时给最终参数赋值之后,在方法体内再也不能改变它的 值。

final修饰的方法不能被子类重写。

final修饰的类不能被继承。

public class TestFinal {
	public static void main(String[] args) {
	T t = new T();
//t.i = 100;
}
}
final class T {
	final int i = 10;
	public final void m() { //j = 11; }
}
	class TT extends T {}

单例模式

在项目中经常会遇到一些功能性的类,那么可以将该类制作成一个单例模式的类,全项目只适用这一个 类来提供服务,节省内存开销。

单例模式的写法有很多

  • 饿汉式
  • 懒汉式
  • 静态内部类
  • 线程锁
  • 双重锁
  • 枚举方式
//饿汉式 --- 简单易用 建议使用
public class Singleton01{
	//私有化构造器
	private Singleton01(){}
	//提供私有静态变量 用来接收单例对象
	private static Singleton01 s1 = new Singleton01();
	//提供静态公共访问方式
	public static Singleton01 getInstance(){
	return s1;
	}
}
//懒汉式 对于饿汉式的加载时创建对象 懒汉式提出使用时创建对象 但存在线程安全问题
public class Singleton02{
	private Singleton02(){}
	private static Singleton02 s2 ;
	public static Singleton02 getInstance(){
	if(null == s2){
	s2 = new Singleton02();
		}
	return s2;
	}
}

多态

Java三大特性之一 多态

同一个事物具有不同形态

对象的多态性:

父类的变量指向子类的对象 或 子类的对象赋值给父类的变量

子类对象和父类对象之间的相互转换 称之为类型转换

子类转父类 无需手动处理 该过程称之为向上转型

但是父类转子类 必须强制类型转换 该过程称之为向下转型 且需要判定当前父类是否是由该子类伪装而 成

判定一个父类是否指向某个具体的子类 需要使用关键字 instanceof 返回值为boolean

•语法:对象变量名 instanceof 类名(或接口名)

class Animal {
	private String name;
	Animal(String name) {
		this.name = name;
}
	public String getName(){
	return name;
}
}
class Cat extends Animal {
	private String eyesColor;
	Cat(String n,String c) {
		super(n); eyesColor = c;
}
	public String getEyesColor(){
		return eyesColor;
}
}
class Dog extends Animal {
	private String furColor;
	Dog(String n,String c) {
		super(n); furColor = c;
}
	public String getFurColor() {
		return furColor;
}
}
public class CastingTest{
	public static void main(String args[]){
	Animal a = new Animal("动物");
		Cat c = new Cat("猫","black");
		Dog d = new Dog("狗","yellow");
	System.out.println(a instanceof Animal);
	System.out.println(c instanceof Animal);
	System.out.println(d instanceof Animal);
	System.out.println(a instanceof Cat);
		//向上转型
	Animal an = new Dog("旺财","yellow");
	System.out.println(an.getName());
	System.out.println(an.getFurColor()); //error!
	System.out.println(an instanceof Animal); //true
	System.out.println(an instanceof Dog); //true
		//向下转型,要加强制转换符
		//-- 为了安全起见,要加 instanceof 判断
	Dog d2 = (Dog)an;
	//Cat c2 = (Cat)an;
	System.out.println(d2.getFurColor());
}
}

使用多态 能够大大提升当前项目的扩展性 并提升代码的复用性

方法的动态绑定

随着程序的执行 父类的方法会获取当前正在指向的子类 并动态绑定至该子类的同名重写方法

动态绑定的要求:

  • 需要继承关系
  • 子类必须重写父类方法
  • 必须有多态性 – 父类变量指向子类对象
  • 父类变量 调用子类重写父类的方法
class Animal {
	private String name;
	public Animal(String name) {this.name = name;
	}
	public void enjoy(){
	System.out.println("叫声......");
	}
}
class Cat extends Animal {
	private String eyesColor;
	public Cat(String n) {super(n);}
	public void enjoy(){
	System.out.println("喵~喵~");
	}
}
class Dog extends Animal {
	private String furColor;
	public Dog(String n) {super(n);}
	public void enjoy(){
	System.out.println("汪~汪~");
	}
}
class Lady{
	private String name;
	private Animal pet;
	public Lady(String name, Animal pet) {
	this.name = name;
	this.pet = pet;
	}
	public void myPetEnjoy(){
	pet.enjoy();
	}
}
public class DynamicBindingTest {
	public static void main(String args[]){
	Cat c = new Cat("catname","blue");
	Lady l = new Lady(“张女士”, c);
	l.myPetEnjoy();
	}
}

抽象类

当一个类中有某些方法不知道如何实现时,可以将该方法定义成抽象方法,只需使用abstract修饰符进 行修饰

抽象方法形式:(没有方法体)

[访问修饰符] abstract 返回类型 方法名(参数列表);

在一个类中如果出现了抽象方法 则该类 必须是抽象类

声明抽象类语法:

[访问修饰符] abstract class 类名{…… }

抽象类特征:

  1. 有构造方法 但是无法调用
  2. 可以有以实现的方法
  3. 可以定义自己的成员属性
  4. 抽象方法的访问修饰符不能是private

用到抽象类其实就是面向父类编程的思想

抽象类的使用:

无法直接通过new来创建对象 需要定义一个类 继承自抽象类 之后重写抽象类中所有未实现方法 如果有 任意一个 抽象方法未实现 则当前类也必须定义为抽象类

abstract class Shape { //形状类
	protected double length; //长
	protected double width; //宽
	public Shape(double length, double width){
	this.length = length; this.width = width;
	}
	public abstract double area(); //计算面积
}
class Rectangle extends Shape { //矩形
	Rectangle(final double num, final double num1) { 			super(num, num1);
}
	public double area() { return length * width; }
	}
class Triangle extends Shape{ //三角形
	Triangle(final double num, final double num1) { 			super(num, num1);
}
	public double area() { return length * width/2; }
	}
	public class TestAbstract{
	public static void main(String[] args){}
}

思考:

  1. 抽象类中可不可以没有抽象方法?
  2. 有抽象方法的类可以可以不是抽象类?

接口

接口就是某个事物对外提供的一些功能的申明 。相当于一个说明书

可以利用接口实现多态,同时也弥补Java单一继承的弱点

使用interface关键字定义接口。

JDK8之前,在接口中所有的方法必须都是抽象方法 且修饰符必须是 public abstract

所有的属性 都必须是静态常量 修饰符为 public static final

如果不定义修饰符 则JVM会在编译过程中自动添加 但是不能出现和语法修饰符相悖的修饰符

接口没有构造方法,所以不能被实例化(不能用来创建对象)。

//方法接口
public interface Runner{
	public void run();
}
//定义常量的接口
public interface Constants{
	public static final int COLOR_RED = 1;
	public static final int COLOR_GREEN = 2;
	public static final int COLOR_BLUE = 3;
}

使用接口可以提升扩展性 降低程序的耦合度

使用接口 也可以认为是面向接口编程

接口的使用

用关键字 implements 实现接口。如:

•class Car implements Runner

每个类只能有一个父类,但可以实现多个接口。如果实现多个接口,则用逗号隔开接口名称,如下所 示:

•class Car implements Runner, Constants

一个类实现了一个接口,它必须实现接口中定义的所有方法,否则该类必须声明为抽象类。

接口可以继承自其它的接口,并添加新的常量和方法。接口支持多重继承

class Car implements Runner,Constants{ //实现两个接口
	public void run(){
	System.out.println("车颜色是:" + COLOR_RED);
	System.out.println("用四个轮子跑...");
	}
}
interface Animal extends Runner{ //接口的继承
	void breathe(); //呼吸
}
class Fish implements Animal{
	public void run(){
	System.out.println("颜色是:" + COLOR_BLUE);
	System.out.println(“游啊游...");
	}
	public void breathe(){
	System.out.println("冒气泡来呼吸");
	}
}

嵌套类

声明在类的内部的类称之为嵌套类(nested class)

//语法定义
[public] class OuterClass{
    ...
	[public|proteceted|private] [static] class NestedClass{
	...
	}
}

嵌套类主要可以分为两大类

  • 静态嵌套类:用static修饰的嵌套类
  • 非静态嵌套类:内部类

嵌套类在编译后会生成OuterClass$NestedClass.class类文件

内部类

内部类作为外部类的一个成员存在,与外部类的成员变量、成员方法并列

class Outer {
	private int outer_i = 100;
	private int j = 123;
	public void test() { System.out.println("Outer:test()"); }
	public void accessInner(){
	Inner inner = new Inner();//外部类中使用内部类也需要创建出它的对象
	inner.display();
}
public class Inner {
	private int inner_i = 100;
	private int j = 789; //与外部类某个属性同名
public void display() {
//内部类中可直接访问外部类的属性
	System.out.println("Inner:outer_i=" + outer_i);
	test(); //内部类中可直接访问外部类的方法
//内部类可以用this来访问自己的成员
	System.out.println("Inner:inner_i=" + this.inner_i);
	System.out.println(j); //访问的是内部类的同名成员
//通过“外部类.this.成员名”来访问外部类的同名成员
	System.out.println(Outer.this.j);
		}
	}
}
//调用测试
public class MemberInnerClassTest {
	public static void main(String[] args) {
		Outer outer = new Outer();
		outer.test();
		outer.accessInner();
//在外部类以外的地方创建内部类的对象
		Outer.Inner inner = outer.new Inner();
		inner.display();
	}
}

静态嵌套类

静态嵌套类中可声明static成员或非静态成员,但只能访问外部类中的静态成员

[public ] class OuterClass{
	...
	static class StaticNestedClass { //静态嵌套类
	...
	}
}

方法类

•方法类(局部内部类):在方法体内声明的类

可访问它所在方法中的final参数和final局部变量

由于线程与并发的原因,局部内部类仅能方法中的final参数和final局部变量。

public class Outer{
	public void test(final int y){
		final int x = 9;//可以访问final修饰的变量
		class FunctionInner{//方法类(局部内部类)
		public void show()
		{
		System.out.println(x+" "+y);
		}
	}
	FunctionInner f = new FunctionInner();//创建方法类对象
	f.show();//调用方法类中的方法
}

匿名内部类

匿名内部类:没有声明名称的内部类

匿名类与方法类相同,仅能访问方法中final的局部变量。

public class AnnonymoseInnerClassTest {
	public static void main(String[] args) {
		(new AClass("redhacker") {
		public void print() { //对父类的print方法进行覆盖
		System.out.println("the anonymose class print");
		super.print(); //调用父类中的print方法
			}
		}).print(); //调用覆盖后的print方法
	}
}
class AClass {
	private String name;
	AClass(String name) { this.name = name;}
	public void print() {
	System.out.println("SuperClass:The name = " + name);
	}
}

说明

  • 方法类和匿名内部类最常见的用处就是实现一个接口,而这个接口通常都只会使用一次,所以不用 专门用一个类去实现它。
  • 比起方法类,匿名类更加简洁。但当类体较长时,这时候就不适合使用匿名类了,而是应该使用方 法类。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

于歌852

您的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值