Java面向对象详解

面向对象

基本概念

对象就是存在的具体实体,具有明确定义的状态和行为,是面向对象编程的核心,用来描述现实世界中的实体,为计算机应用程序提供实体基础,也是完成特定任务一个封装。

面向过程思想,强调的是过程(动作).
面向对象思想,强调的是对象(实体)。
特点:
1,面向对象就是一种常见的思想。符合人们的思考习惯。
2,面向对象的出现,将复杂的问题简单化。
3,面向对象的出现,让曾经在过程中的执行者,变成了对象中的指挥者。

类和对象关系

类:事物的描述
对象:该类事物的实例。在Java中通过new来创建

描述对象

对于事物描述通常只关注两方面。
1.属性
2.行为:运行
只要明确该事物的属性和行为并定义在类中即可。

定义类其实就是在定义类中的成员。
成员:成员变量<–>属性,成员函数<–>行为。

成员变量和局部变量的区别:

成员变量定义在类中,整个类中都可以访问
局部变量定义在函数,语句,局部代码块中,只在所属的区域有效。
成员变量存在于堆内存的对象中
局部变量存在于栈内存的方法中
成员变量随着对象的创建而存在,随着对象的消失而消失
局部变量随着所属区域执行而存在,随着所属区域的结束而释放
成员变量都有默认初始化值
局部变量没有默认初始化值

默认初始化和显示初始化

匿名对象:当对像对方法仅进行一次调用的时候,可以简化成匿名对象。

new Car().num=5;
new Car().color="green";
new Car().run();

基本数据类型参数传递
引用数据类型参数传递

封装

代码块。
1,局部代码快。
对局部变量的生命周期进行控制。
2,构造代码块。
对所有对象进行初始化。
3,静态代码块。
对类进行初始化。
private:私有,是一个权限修饰符。用于修饰成员。
私有的内容只在本类中有效。
注意:私有仅仅是封装的一种体现而已。

构造函数(方法)

(构建创造对象时调用的函数)作用:可以给对象初始化(创建对象都必须要通过构造函数初始化)
特点
函数名与类名相同
不用定义返回值类型
没有具体的返回值
一个类中如果没有定义过构造函数,那么该类中会有一个默认的空参数构造函数。
如果在类中定义了指定的构造函数,那么类中的默认构造函数就没有了。

//无参构造函数
public Dog(){}//如果一个类没有定义构造方法,则默认无参构造,如果定义有参构造,最好在显示定义一个无参构造方法。
//带参构造方法:
public Dog(String name)
{
	this.name = name;
}
//多参构造方法:
public Dog(String name,int age)
{
	this.name = name;
	this.age = age;
}

重载特点:
方法名相同参数列表不一样

一般函数(方法)和构造函数(方法)区别

构造函数:对象创建时,就会调用与之对应的构造函数,对对象进行初始化。
一般函数:对象创建后,需要函数功能时才调用。

构造函数:对象创建时,会调用只调用一次。
一般函数:对象创建后,可以被调用多次。

什么时候定义构造函数呢?

在描述事物时,该事物一存在就具备的一些内容,这些内容都定义在构造函数中。
构造函数可以有多个,用于对不同的对象进行针对性的初始化.
多个构造函数在类中是以重载的形式来体现的。

细节:

1,构造函数如果完成了set功能。set方法是否需要。
2,一般函数不能直接调用构造函数。
3,构造函数如果前面加了void就变成了一般函数。
4,构造函数中是有return语句的。

(1)构造方法名称与类名相同,没有返回值声明(包括 void)
(2)构造方法用于初始化数据(属性)
(3)每一个类中都会有一个默认的无参的构造方法
(4)如果类中有显示的构造方法,那么默认构造方法将无效
(5)如果有显示的构造方法,还想保留默认构造方法,需要显示的写出来。
(6)构造方法可以有多个,但参数不一样,称为构造方法的重载
(7)在构造方法中调用另一个构造方法,使用this(…),该句代码必须在第一句。
(8)构造方法之间的调用,必须要有出口。
(9)给对象初始化数据可以使用构造方法或setter方法,通常情况下,两者都会保留。
(10)一个好的编程习惯是要保留默认的构造方法。(为了方便一些框架代码使用反射来创建对象)
(11)private Dog(){},构造方法私有化,当我们的需求是为了保正该类只有一个对象时(单例模式就是私有化构造器)。

主函数(main)方法分析

public static void main(String[] args) 

主函数特殊之处:
1,格式是固定的。
2,被jvm所识别和调用。
public:因为权限必须是最大的。
static:不需要对象的,直接用主函数所属类名调用即可。
void:主函数没有具体的返回值。
main:函数名,不是关键字,只是一个jvm识别的固定的名字。
String[] args:这是主函数的参数列表,是一个数组类型的参数,而且元素都是字符串类型。

this

当成员变量和局部变量重名,可以用关键字this来区分。
this关键字指向的是当前对象的引用(代表所在函数所属对象的引用)
调用类中的属性:this.属性名称,指的是访问类中的成员变量,用来区分成员变量和局部变量(重名问题)
调用类中的方法:this.方法名称,用来访问本类的成员方法
调用类构造方法:this();访问本类的构造方法,()中可以有参数的 如果有参数 就是调用指定的有参构造
注意:
1.this() 不能使用在普通方法中,只能写在构造方法中
2.必须是构造方法中的第一条语句,因为初始化动作要先执行。
this : 代表当前对象。
this就是所在函数所属对象的引用。
简单说:哪个对象调用了this所在的函数,this就代表哪个对象。
this也可以用于在构造函数中调用其他构造函数。

static

static关键字的作用:方便在没有创建对象的情况下来进行调用(方法/变量)。
a、使用static关键字修饰一个属性:声明为static的变量实质上就是全局变量
b、使用static关键字修饰一个方法:在一个类中定义一个方法为static,那就是说,无需本类的对象即可调用此方法(类调用)
c、使用static关键字修饰一个类(内部类):

static的特点:

1,static是一个修饰符,用于修饰成员。声明为static的变量实质上就是全局变量
2,static修饰的成员被所有的对象所共享。
3,static优先于对象存在,因为static的成员随着类的加载就已经存在了。
4,static修饰的成员多了一种调用方式,就可以直接被类名所调用 。 格式:类名.静态成员 。
5,static修饰的数据是共享数据,对象中的存储的是特有数据。

成员变量和静态变量的区别

1,两个变量的生命周期不同。
成员变量随着对象的创建而存在,随着对象的被回收而释放。
静态变量随着类的加载而存在,随着类的消失而消失。
2,调用方式不同。
成员变量只能被对象调用。
静态变量可以被对象调用,还可以被类名调用。
3,别名不同。
成员变量也称为实例变量。
静态变量称为类变量。
4,数据存储位置不同。
成员变量数据存储在堆内存的对象中,所以也叫对象的特有数据.
静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据.

静态使用的注意事项:

1,在static方法内部不能调用非静态方法(非静态既可以访问静态,又可以访问非静态)
2,静态方法中不可以使用this或者super关键字。
3,主函数是静态的。
4,不允许用来修饰局部变量

静态什么时候用?

1,静态变量。
当分析对象中所具备的成员变量的值都是相同的 。
这时这个成员就可以被静态修饰。
只要数据在对象中都是不同的,就是对象的特有数据,必须存储在对象中,是非静态的。
如果是相同的数据,对象不需要做修改,只需要使用即可,不需要存储在对象中,定义成静态的。

2,静态函数。
函数是否用静态修饰,就参考一点,就是该函数功能是否有访问到对象中的特有数据。
简单点说,从源代码看,该功能是否需要访问非静态的成员变量,如果需要,该功能就是非静态的。
如果不需要,就可以将该功能定义成静态的。当然,也可以定义成非静态,
但是非静态需要被对象调用,而仅创建对象调用非静态的
没有访问特有数据的方法,该对象的创建是没有意义。

3,静态代码块:
随着类的加载而执行。而且只执行一次。
作用:
用于给类进行初始化。

super关键字

可以理解为对父类的引用,使用super来调用父类的属性,方法,和构造方法
super可以完成以下的操作:
a、使用super调用父类中的属性,可以从父类实例处获得信息。
b、使用super调用父类中的方法,可以委托父类对象帮助完成某件事情。
c、使用super调用父类中的构造方法(super(实参)形式),必须在子类构造方法的第一条语句,调用父类中相应的构造方法,若不显示的写出来,默认调用父类的无参构造方法,比如:super();

继承

//Java 的继承是单继承,但是可以多重继承,

语法:[访问权限] class 子类名 extends 父类名{
  类体定义;
}

//示例:
public class Dog{
private String name;
private String sex;
public void eat(){System.out.println(“吃饭”);}
}
public class HomeDog extends Dog{
  //类的定义
}
public class HuskyDog extends Dog{
  //类的定义
}

//protected(受保护的访问权限修饰符,用于修饰属性和方法,使用protected修饰的属性和方法可以被子类继承)

作用域 当前类 同一package 子孙类 其他package
public √ √ √ √
protected √ √ √ ×
friendly √ √ × ×
private √ × × ×

继承的好处:

1,提高了代码的复用性。
2,让类与类之间产生了关系,给第三个特征多态提供了前提.

java中支持单继承。不直接支持多继承,但对C++中的多继承机制进行改良。
单继承:一个子类只能有一个直接父类。
多继承:一个子类可以有多个直接父类(java中不允许,进行改良)
不直接支持,因为多个父类中有相同成员,会产生调用不确定性。
在java中是通过"多实现"的方式来体现。

C继承B,B继承A。
就会出现继承体系。

当要使用一个继承体系时,
1,查看该体系中的顶层类,了解该体系的基本功能。
2,创建体系中的最子类对象,完成功能的使用。

什么时候定义继承呢?
当类与类之间存在着所属关系的时候,就定义继承。xxx是yyy中的一种。 xxx extends yyy

所属关系: is a 关系。

在子父类中,成员的特点体现

1,成员变量。
当本类的成员和局部变量同名用this区分。
当子父类中的成员变量同名用super区分父类。
this和super的用法很相似。
this:代表一个本类对象的引用。
super:代表一个父类空间。

2,成员函数。
当子父类中出现成员函数一模一样的情况,会运行子类的函数。
这种现象,称为覆盖操作。这时函数在子父类中的特性。
函数两个特性:
1,重载。同一个类中。overload
2,覆盖。子类中。覆盖也称为重写,覆写。override
覆盖注意事项:
1,子类方法覆盖父类方法时,子类权限必须要大于等于父类的权限。
2,静态只能覆盖静态,或被静态覆盖。
什么时候使用覆盖操作?
当对一个类进行子类的扩展时,子类需要保留父类的功能声明,
但是要定义子类中该功能的特有内容时,就使用覆盖操作完成.

3,构造函数
子父类中的构造函数的特点。
在子类构造对象时,发现,访问子类构造函数时,父类也运行了。
原因是:在子类的构造函数中第一行有一个默认的隐式语句。 super();

子类的实例化过程:子类中所有的构造函数默认都会访问父类中的空参数的构造函数。
(构造函数没有覆盖,构造函数不能继承)

问题

1,为什么子类实例化的时候要访问父类中的构造函数?
因为子类继承了父类,获取到了父类中内容(属性),所以在使用父类内容之前,
要先看父类是如何对自己的内容进行初始化的。
所以子类在构造对象时,必须访问父类中的构造函数。
2,为什么完成这个必须的动作,就在子类的构造函数中加入了super()语句。
因为如果父类中没有定义空参数构造函数,那么子类的构造函数必须用super明确要调用父类中哪个构造函数。同时子类构造函数中如果使用this调用了本类构造函数时,那么super就没有了,因为super和this都只能定义第一行。所以只能有一个。但是可以保证的是,子类中肯定会有其他的构造函数访问父类的构造函数。
注意:supre语句必须要定义在子类构造函数的第一行。因为父类的初始化动作要先完成。

覆盖注意事项:

1,子类方法覆盖父类方法时,子类权限必须要大于等于父类的权限。
2,静态只能覆盖静态,或被静态覆盖。
什么时候使用覆盖操作?
当对一个类进行子类的扩展时,子类需要保留父类的功能声明,
但是要定义子类中该功能的特有内容时,就使用覆盖操作完成.

注意:super语句必须要定义在子类构造函数的第一行,父类的初始化动作要先完成。

/*
 所有类默认有注释里的内容
通过super初始化父类的内容,子类成员变量并未显示初始化。等super()父类初始化完毕后,才进行子类的成员变量显示初始化。
*/
class Demo //extend Object
{
	/*
	Demo()
	{
		super();
		return;
	}
	*/
}
什么时候使用覆盖操作?

当对一个类进行子类的扩展时,子类需要保留父类的功能声明,
但是要定义子类中该功能的特有内容时,就使用覆盖操作完成.

一个对象实例化过程:

Person p = new Person();
1,JVM会读取指定的路径下的Person.class文件,并加载进内存,
并会先加载Person的父类(如果有直接的父类的情况下).
2,在堆内存中的开辟空间,分配地址。
3,并在对象空间中,对对象中的属性进行默认初始化。
4,调用对应的构造函数进行初始化。
5,在构造函数中,第一行会先到调用父类中构造函数进行初始化。
6,父类初始化完毕后,在对子类的属性进行显示初始化。
7,在进行子类构造函数的特定初始化。
8,初始化完毕后,将地址值赋值给引用变量.

单例设计模式

//饿汉式

class single
{
       private static Single s = new Single();
private Single(){}
public static Single getInstance()
{
return s;
}
}
//懒汉式 (多线程并发访问时不能保证对象唯一性,存在安全唯一性)
class single2
{
       private static Single2 s = null;
private Single(){}
public static Single2 getInstance()
{
if(s==null)
       s = new Single2()
return s;
}
}

final关键字:

继承弊端:继承会打破封装性
final是一个修饰符可以修饰类、方法、变量。
final修饰的类不可以被继承。
final 修饰的方法不可以被覆盖。
final修饰的变量是一个常量,只能赋值一次。
为什么使用final关键字修饰变量,在程序中一个数据如果是固定的,那么直接使用这个数据就可以,
但是这样阅读性差,所以给该数据定义一个变量名称,而且这个变量名称的值不能变化,所以加上final固定。
写法规范:常量所有字母都大写,多个单词中间用_连接。

抽象类:

抽象 :笼统,模糊,看不懂,不具体。

特点:

  1. 方法只有声明没有实现是,该方法就是抽象方法,需要被abstract修饰。抽象方法必须定义在抽象类中,该类也必须被abstract修饰
  2. 抽象类不能被实例化,因为调用抽象方法无意义。
  3. 抽象类必须有其子类覆盖了所有的抽象方法后,该子类才可以实例化,否则,这个子类还是抽象类。
细节:

抽象类中有构造函数吗?
有,给子类对象进行初始化
抽象类可以不定义抽象方法吗?
可以,少见,目的是为了不让该类创建对象。AWT的适配器对象就是这种类。通常这个类中的方法有方法体,但是却没内容。
抽象关键字不可以和以下关键字共存:
private 抽象类需要被覆盖
static
final

抽象类和一般类的异同?

同:都是用来描述事物,都在内部 定义了成员。
异:
1有足够的信息描述事物
2描述事物信息可可能不足
1不能定义抽象方法,只能定义非抽象方法
2可以定义抽象方法也可以定义非抽象方法
1可以被实例化
2不可被实例化
抽象类一定是个父类吗?
是的。因为需要子类覆盖其方法后才可以对子类实例化。

接口

特点:

接口是对外暴露的规则
是程序的功能扩展
降低耦合性
可以用来多实现
类与接口之间是实现关系,类可以继承一个类的同时实现多个接口
接口和接口之间可以有继承关系

格式 :

interface 类名{}

当一种抽象类中的方法都是抽象的时候,这时可以将该抽象类 用另一种形式定义和表示,接口:interface
定义接口使用的关键字不是class,是interface
对于接口当中常见的成员都有固定的修饰符
1全局变量:public static final
2抽象方法:public abstract
结论:接口中的成员都是公共的权限。
实现
类与类是继承关系,类与接口之间是实现(接口里有的都要被覆盖)关系,格式:

class DemoImpl implements/*实现*/Demo
{}

接口不可以实例化:
只能由实现了接口的子类并覆盖接口中的所有抽象方法后,该子类可以实例化。否则下一个子类就是抽象类。

接口的出现避免了单继承的局限性。
多实现:

interface A
{
	public void show();
}
interface Z
{
	public int add(int a,int b);
}
class Test implements A,Z//多实现
{
	public int add(int a,int b)
	{
		return a+b+3;	
	}
	/**/
	public void show(){}
}
/*
一个类在继承另一个类的同时,还可以实现多个接口。
*/
class Q
{
	public void method()
	{}
}
abstract class Test2 extends Q implements A,Z
{

}

接口与接口之间是继承关系,而且接口可以是多继承。接口没有方法体

interface CC
{
	void show();
}
interface MM
{
	void method();
}
interface QQ extends  CC,MM//接口与接口之间是继承关系,而且接口可以多继承。 
{
	void function();
}

抽象类和接口的异同点
同:都是向上抽取而来的

1抽象类需要被继承,而且只能单继承
接口需要被实现,而且可以多实现
2抽象类中可以定义抽象方法和非抽象方法,子类继承后,可以直接使用非抽象方法。
接口中只能定义抽象方法,必须由子类去实现。
3抽象类的继承,是is a关系,在定义该体系的基本共性内容。
接口的实现是like a关系,在定义体系额度外功能。
注:Java中接口也称规则

多态

对象的多态性:一个对象对应着不同类型
多态在对象中的体现:父类或者接口的引用指向其子类的对象
好处:提高了代码的扩展性,前期定义的代码可以使用后期的内容
弊端:前期定义的内容不能使用(调用)后期子类的特有功能
多态前提:
必须要有关系,继承实现。
要有覆盖

多态转型:
向上转型:自动类型提升:byte b = 3,int a=b;
作用:限制对象特有功能的访问。向上转型:将子类型隐藏,就不用使用子类的特有方法。
向下转型:目的为了使用子类中的特有方法。


/*
对象的多态性。

class 动物
{}

class 猫 extends 动物
{}

class 狗 extends 动物
{}
猫 x = new 猫();
动物 x = new 猫();//一个对象,两种形态

猫这类事物即具备者猫的形态,又具备着动物的形态。
这就是对象的多态性。 
*/

abstract class Animal
{
	abstract void eat();

}

class Dog extends Animal
{
	void eat()
	{
		System.out.println("啃骨头");
	}
	void lookHome()
	{
		System.out.println("看家");
	}
}

class Cat extends Animal
{
	void eat()
	{
		System.out.println("吃鱼");
	}
	void catchMouse()
	{
		System.out.println("抓老鼠");
	}
}

class Pig extends Animal
{
	void eat()
	{
		System.out.println("饲料");
	}
	void gongDi()
	{
		System.out.println("拱地");
	}
}



class DuoTaiDemo 
{
	public static void main(String[] args) 
	{
		
//		Cat c = new Cat();
//		c.eat();
//		c.catchMouse();

		Animal a = new Cat(); //自动类型提升,猫对象提升了动物类型。但是特有功能无法访问。
							//作用就是限制对特有功能的访问。
							//专业讲:向上转型。将子类型隐藏。就不用使用子类的特有方法。


//		a.eat();

		//如果还想用具体动物猫的特有功能。 
		//你可以将该对象进行向下转型。
//		Cat c = (Cat)a;//向下转型的目的是为了使用子类中的特有方法。
//		c.eat();
//		c.catchMouse();

//		注意:对于转型,自始自终都是子类对象在做着类型的变化。
//		Animal a1 = new Dog();
//		Cat c1 = (Cat)a1;//ClassCastException


		/*
		Cat c = new Cat();

//		Dog d = new Dog();

//		c.eat();
		method(c);
//		method(d);
//		method(new Pig());
		*/

		method(new  Dog());

	}

	public static void method(Animal a)//Animal a = new Dog();
	{
		a.eat();

		if(a instanceof Cat)//instanceof:用于判断对象的具体类型。只能用于引用数据类型判断
//						//通常在向下转型前用于健壮性的判断。

		{
			Cat c = (Cat)a;
			c.catchMouse();
		}
		else if(a instanceof Dog)
		{
			Dog d = (Dog)a;
			d.lookHome();
		}
		else
		{
		
		}
		
	}
	/*
	public static void method(Cat c)
	{
		c.eat();
	}
	public static void method(Dog d)
	{	
		
	}
	*/	
}

注意:对于转型,自始至终都是子类对象在做着类型的变化。
多态类型判断:instanceof用于判断对象的具体类型,只能用于引用数据类型判断。通常在向下转型前用于健壮性的判断。

多态时成员的特点:
  1. 成员变量
    编译时参考引用型变量所属的类中是否有调用的成员变量,有编译通过,无,编译失败。
    运行时参考引用型变量所属的类中是否有调用的成员变量,并运行该所属类的成员变量。
    编译运行都参考等号左边。
  2. 成员函数(非静态)
    编译时参考引用型变量所属的类中是否有调用的成员变量,有编译通过,无,编译失败。
    运行时参考对象所属的类中是否有调用的函数
    编译看左边,运行看右边。
  3. 静态函数
    编译时:参考引用型变量所属的类中的是否有调用的静态方法。
    运行时:参考引用型变量所属的类中的是否有调用的静态方法。
    编译和运行都看左边。
    其实对于静态方法,是不需要对象的。直接用类名调用即可。

内部类

内部类访问特点

1内部类可以直接访问外部类中的成员。
2外部类要访问内部类,必须建立内部类的对象。

直接访问外部类中内部类的成员

class Outer
{
	private static int num = 31;
	class Inner// 内部类。
	{
		void show()
		{
			System.out.println("show run..."+num);
		}
		/*static void function()//如果内部类中定义了静态成员,该内部类也必须是静态的。
		{
			System.out.println("function run ...."+num);
		}
		*/
	}
	public void method()
	{
		Inner in = new Inner();
		in.show();
	}
}
class InnerClassDemo
{
	public static void main(String[] args) 
	{
		Outer out = new Outer();
		out.method();
		//直接访问外部类中的内部类中的成员。
    //    Outer.Inner in = new Outer().new Inner();
	//	in.show();

		//如果内部类是静态的。 相当于一个外部类
	//	Outer.Inner in = new Outer.Inner();
	//	in.show();

		//如果内部类是静态的,成员是静态的。
	//	Outer.Inner.function();
	}
}

调用格式:外部类.内部类 in = new 外部类().new 内部类();
如果内部类是静态的,相当于一个外部类
调用格式:外部类.内部类 in = new 外部类.内部类();
in 方法名();
如果内部类是静态的,成员变量是静态的
外部类.内部类.方法名();
如果内部类定义了静态成员该类也必须是静态
为什么内部类能直接访问外部类中的成员呢?
因为内部类持有了外部类的引用。外部类名.this

内部类也可以存放在局部位置上
内部类在局部位置上只能访问局部中被final修饰的变量。

class Outer
{	
	int num = 3;
	Object method()
	{
		final int x = 9;//只能访问9
		class Inner
		{
			public String toString()
			{
				return "show ..."+x;//x=9
			}
		}	
	}
}

匿名内部类:就是内部类的简写格式
前提:内部类必须继承或实现一个外部类或接口
匿名内部类就是一个匿名子类对象。
格式:
new 父类or接口(){子类内容};
调用方法:
new 父类or接口(){子类内容}.方法();=new 内部类.方法();

使用场景之一:当函数参数是接口类型时,而且接口中的方法不超过三个。可以使用匿名内部类作为实际参数进行传递。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值