Java面向对象和类进阶

1.面向对象

现实世界是由对象和对象之间相互作用共同组成的;
每个对象都有自己的特有属性,也有自己专有的方法。对象要调用这些方法,可以向它请求并传入参数,等方法执行结束后,返回结果;

对象=属性+方法
对象的规范=属性定义+方法定义

Java中的对象和类的概念

  • 对象是一个变量,一个具体的事物
  • 类就是类型,从许多对象中抽取共性
  • 类规定了对象应该有的属性内容和方法
  • 对象是类的具体实现

基本类型是一种变量
结构体是多种变量的集合
类是多种变量和方法的集合

2.Java类

Java项目是由一个个类组成的

类是Java中的基础逻辑单元:
java所有的内容都要放在类的范围中

类的构成:

  1. 成员变量/属性
  • 局部变量:在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。
  • 成员变量:成员变量是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。
  • 类变量:类变量也声明在类中,方法体之外,但必须声明为static类型。
  1. 成员方法/函数

public class MemberShow 
{
	int a=0;  //成员变量  member variables
	int b=5;
	
	//不允许在这里写 System.out.println("hello");  既不是变量也不是函数,非法
	
	public void f1()   //成员函数  member functions
	{
		System.out.println("Hello");
	}
}

//不允许在这里写 System.out.println("hello")

Main函数

一个class最多只能有一个main函数(固定写法public static void main()——PSVM类型)类可以没有main函数,没有main函数的类不能主动执行,但可以被动执行,即被别人调用执行
程序的入口都是main函数,但与C/C++不同的是,代码都要放在class内
main函数是一个Java程序的总入口
mian函数无法被其他方法/类调用
一个Java程序可以调用多个其他Java class

String[] args是main函数的形参,即在main函数中可以使用args的值(在main函数启动时输入)


public class ArgumentTest 
{
	public static void main(String[] args) 
	{
		for(int i=0;i<args.length;i++)
		{
			//依次将形参输出
			System.out.println(args[i]);
		}
	}
}

注意:
Java文件必须以.java为扩展名
一个Java文件可以有多个类,但只能有一个public class
public class的名字必须和文件名字一样(大小写也一致)

类可以继承,子类可以继承父类所有内容(不能直接访问private成员)


public class Father {
	private int money = 100;  //私有
	long mobile = 13999999999L;
	
	public void hello()	{
		System.out.println("hello");
	}
}

public class Son extends Father {
	public void hi() {
		//子类可以扩展自己的成员方法
		System.out.println("hi~~~~~");
	}
	
	public static void main(String[] a)	{
	    Son s = new Son();
	    System.out.println(s.mobile); //Son没有定义mobile, 而是通过父类继承的
	    //System.out.println(s.money); //error 父类的money是私有的,子类无法直接访问
	    s.hello();  //Son没有定义f1, 而是通过父类继承的
	    s.hi();     //Son可以自定义自己的成员方法
	}
}

new方法产生对象,对象是类的实现,是实例。


public class ReferenceTest {

	public static void main(String[] args) {
		
		int num1 = 5;
		int num2 = num1;
		System.out.println("num1: " + num1 + ", num2: " + num2);
		num2 = 10;
		System.out.println("num1: " + num1 + ", num2: " + num2);
		
		
		MyNumber obj1 = new MyNumber(); //num=5
		MyNumber obj2 = new MyNumber();
		System.out.println(obj1.num);
		System.out.println(obj2.num);
		System.out.println("======接下来输出新值=====");
		
		obj2 = obj1;
		obj2.num = 10;     //obj1和obj2指向同一块内存
		
		System.out.println(obj1.num);
		System.out.println(obj2.num);

	}

}

以上实例两个对象,类型都是A,但是是两个不同的对象,在内存中有不同的存放地址。
在这里插入图片描述
对象赋值是赋值,而基本类型是直接值拷贝

//对象复制是Refence赋值,而基本类型是直接值拷贝
//因为基本类型变量值小,可直接拷贝;对象包含多个值,不容易复制,复制采用共享同一块内存区域
public class ArgumentPassingTest {

	public static void main(String[] args) {
		int a = 1, b = 2;
		swap(a,b);  //交换
		System.out.println("a is " + a + ", b is " + b);  //a=1, b=2
		
		MyNumber obj1 = new MyNumber();
		MyNumber obj2 = new MyNumber();
		obj2.num = 10;
		swap(obj1, obj2);
		System.out.println("obj1 is " + obj1.num + ", obj2 is " + obj2.num);  //  obj1  10,   obj2  5

	}
	public static void swap(int m, int n)   //调用时m=1,n=2
	{                                       //m,n交换 与a,b无关
		int s = m;
		m = n;
		n = s;
	}
	public static void swap(MyNumber obj3, MyNumber obj4)  //obj1和obj3指向同一块内存
	{
		int s = obj3.num;
		obj3.num = obj4.num;
		obj4.num = s;
	}

}

3.继承

面向对象编程的特点是变量类型的继承,避免了面向过程编程的类型重复定义问题

子类继承父类所有的属性和方法,但不能直接访问private成员
根据信息隐藏原则:子类会继承父类所有的方法,可以直接使用
子类也会继承父类的父类的所有属性和方法,但不能直接访问private成员
单根继承原则:每个类都只能继承一个类
如果不写extends,Java类默认继承java.long.Object类

每个Java类都必须有构造函数
如果没有显式定义构造函数,Java编译器自动为该类产生一个空的无形参构造函数,如果已经有了显式的有参构造函数,编译器就不会自动产生。
每个子类构造函数的第一句话,都默认调用父类的无参构造函数super(),除非子类的构造函数第一句话是super,而且super语句必须放在第一条,不会出现连续的两条super语句


public class A {
	public A()
	{
		System.out.println("111111");
	}
	public A(int a)
	{
		System.out.println("222222");
	}
}

public class B extends A{
	public B()
	{
		//super(); 编译器自动增加super()
		System.out.println("333333");
	}
	public B(int a)
	{
		super(a);  //编译器不会自动增加super();
		System.out.println("444444");
	}
	public static void main(String[] a)
	{
		B obj1 = new B();
		System.out.println("==============");
		B obj2 = new B(10);		
	}

}

this关键字

class Animal {
  void eat() {
    System.out.println("animal : eat");
  }
}
 
class Dog extends Animal {
  void eat() {
    System.out.println("dog : eat");
  }
  void eatTest() {
    this.eat();   // this 调用自己的方法
    super.eat();  // super 调用父类方法
  }
}
 
public class Test {
  public static void main(String[] args) {
    Animal a = new Animal();
    a.eat();
    Dog d = new Dog();
    d.eatTest();
  }
}

static关键字
静态变量,类公有成员
static变量只依赖于类存在(通过类即可访问),不依赖与对象实例存在
所有的对象实例的值都共享存储在一个共同的空间

静态方法无需通过对象来引用,而通过类名可以直接引用;
在静态方法中,只能使用静态变量,不能使用非静态变量;
静态方法禁止引用非静态方法;
static块只在第一次被加载时调用(即在过程中只运行一次);
执行顺序:static块>匿名块>构造函数


public class Potato {
	static int price = 5;
	String content = "";
	public Potato(int price, String content)
	{
		this.price = price;
		this.content = content;
	}	
	public static void main(String[] a)
	{
		System.out.println(Potato.price); //Potato.content    wrong
		System.out.println("----------------------------------");
		Potato obj1 = new Potato(10,"青椒土豆丝");
		System.out.println(Potato.price); //10
		System.out.println(obj1.price);   //10
		
		System.out.println("----------------------------------");
		Potato obj2 = new Potato(20,"酸辣土豆丝");
		System.out.println(Potato.price);  //20
		System.out.println(obj2.price);    //20
		
	}
}

final关键字:
final的类,不能被继承(父类中如果有final方法,子类中不能改写此方法)
final的变量,不能再次赋值

如果是基本类型的变量,不能修改其值
如果是对象实例,不能修改其指针,但可以修改对象内部的值

class FinalObject
{
	int a = 10;
}

public class FinalObjectTest {

	public static void main(String[] args) {
		final FinalObject obj1 = new FinalObject();
		System.out.println(obj1.a);
		obj1.a = 20;
		System.out.println(obj1.a);
		
		//obj1 = new FinalObject();  Wrong
		//final对象不能变更指针
	}

}

java继承是单继承,也可以多重继承

4.抽象类和接口

一个完整的类所有的方法都要实现
类可以没有方法,但是有方法要有实现才是一个完整的类
一个完整的类才可以被实例化,被new
如果一个类暂时有方法没有实现,需要被定义为抽象类

抽象类用关键字abstract声明
抽象类的组成:
成员变量,具体方法,抽象方法(一个或多个)

注意:一个类继承于抽象类,就不能继承于其他的(抽象)类
子类可以继承与抽象类,但是一定要实现父类们所有abstract的方法,如果不能完全实现,那么子类也必须被定义为抽象类
只有实现父类们的所有抽象方法,才变成完整类

接口:
如果所有类的所有方法都没有实现,那么这个类就算是接口interface
接口是“特殊”的类
类只可以继承(extends)一个类,但是可以实现(implements)多个接口,继承和实现可以同时。

接口可以继承(多个)接口,没有实现的方法将会叠加
类实现接口,就必须实现所有未实现的方法,如果没有全部实现,就只能成为一个抽象类

抽象类和接口两者都不能被实例化,不能new操作
区别是抽象类可以有部分实现,接口所有方法不能有实现;一个类只能继承一个抽象类,实现多个接口;
接口可以继承多个接口。
抽象类有构造函数,接口没有构造函数。

//Animal接口
public interface Animal {
	public void eat();
	public void move();
}

//ClimbTree接口
public interface ClimbTree {
	public void climb();
}

//LandAnimal抽象类
public abstract class LandAnimal implements Animal {

	public abstract void eat() ;

	public void move() {
		System.out.println("I can walk by feet");
	}
}
//Rabbit类
public class Rabbit extends LandAnimal implements ClimbTree {

	public void climb() {
		System.out.println("Rabbit: I can climb");		
	}

	public void eat() {
		System.out.println("Rabbit: I can eat");		
	}
}

5.转型和多态

转型

变量支持相互转换,比如int a=(int)3.5;
类型可以相互转换,但是只限制于有继承关系的类。

子类可以转换成父类,而父类不可以转为子类。
子类继承父类所有的财产,子类可以变成父类(从大变小,即向上转型);
从父类直接变成子类(从小变大,即向下转型)则不允许。

父类可以转换成子类的一种例外情况,就是这个父类本身就是从子类转换来的


public class Human {
	int height;    
    int weight;
    
    public void eat()  {
    	System.out.println("I can eat!");
    }
}

public class Man extends Human {
	public void eat() {
		System.out.println("I can eat more");//子类重写父类eat方法
	}
	
	public void plough() { }   //父类没有的方法

	public static void main(String[] a)	{
		Man obj1 = new Man();
		obj1.eat();   // call Man.eat()
		Human obj2 =  (Human) obj1;  //转型成父类
		obj2.eat();   // call Man.eat()
		Man obj3 = (Man) obj2;       //
		obj3.eat();	  // call Man.eat()
	}
}

多态

多态的定义

同一操作作用于不同类的实例,将产生不同的执行结果,即不同类的对象收到相同的消息时,得到不同的结果

多态性的两种类型

  • 静态多态性

是指定义在一个类或一个函数中的同名函数,它们根据参数表(类型以及个数)区别语义和执行的功能
程序在编译时,系统就能决定调用哪个函数,如重载。

  • 动态多态性

指定义在一个类层次下的不同类中的覆盖函数,它们具有相同的函数原型,需要根据指针指向的对象的所在类来区别语义
在运行中才能动态确定操作指针所指的对象,主要通过虚函数和重写来实现。

子类继承父类的所有方法,但子类可以重新定义一个名字,参数和父类一样的方法,但这种行为就是重写(overwrite),不同于重载(overload)
子类的方法的优先级高于父类的

多态的作用:

  1. 提高了程序的灵活性,提高了编程效率,程序员可以使用统一形式实现不同功能的调用,如以统一的接口来操纵某一类中不同的对象的动态行为。
  2. 对象之间的解耦
//Animal接口
public interface Animal {
	public void eat();
	public void move();
}

//Cat类
public class Cat implements Animal     //继承animal
{
	public void eat() {
		System.out.println("Cat: I can eat");
	}
	
	public void move(){
		System.out.println("Cat: I can move");
	}
}
//Dog类
public class Dog implements Animal     //继承animal
{
	public void eat() {
		System.out.println("Dog: I can eat");
	}
	
	public void move() {
		System.out.println("Dog: I can move");
	}
}

public class AnimalTest {
	
	public static void haveLunch(Animal a)	{
		a.eat();           //调用eat方法,27行
	}
	
	public static void main(String[] args) {
		Animal[] as = new Animal[4];     //new animal数组
		as[0] = new Cat();   //隐含cat转型成animal父类
		as[1] = new Dog();
		as[2] = new Cat();
		as[3] = new Dog();
		
		for(int i=0;i<as.length;i++) {         //多态:以统一的接口来操纵某一类中不同的对象的动态行为
			as[i].move();  //调用每个元素的自身的move方法(子类的)
		}
		for(int i=0;i<as.length;i++) {         //多态另一作用:解耦
			haveLunch(as[i]);
		}
		
		haveLunch(new Cat());  //Animal  a = new Cat();  haveLunch(a);
		haveLunch(new Dog());
		haveLunch(
				new Animal() //animal接口,本来不可以new,但补全方法 匿名的类
				{
					public void eat() {
						System.out.println("I can eat from an anonymous class");						
					}
					public void move() {
						System.out.println("I can move from an anonymous class");
					}
					
				});
	}
}
//子类转型为父类后,调用普通方法,依旧是子类的方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值