黑马程序员java之面向对象封装与继承



------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ----------


面向对象:


特点:1:将复杂的事情简单化。

 2:面向对象将以前的过程中的执行者,变成了指挥者。

 3:面向对象这种思想是符合现在人们思考习惯的一种思想。


 

类和对象的关系

类就是:对现实生活中事物的描述。

对象:就是这类事物,实实在在存在个体。

属性对应是类中变量,行为对应的类中的函数(方法)

其实定义类,就是在描述事物,就是在定义属性和行为。属性和行为共同成为类中的成员(成员变量和成员方法)


在类中定义其实都称之为成员。成员有两种:

1:成员变量:其实对应的就是事物的属性。

2:成员函数:其实对应的就是事物的行为。


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

1:成员变量直接定义在类中。

  局部变量定义在方法中,参数上,语句中。

2:成员变量在这个类中有效。

局部变量只在自己所属的大括号内有效,大括号结束,局部变量失去作用域。

3:成员变量存在于堆内存中,随着对象的产生而存在,消失而消失。

局部变量存在于栈内存中,随着所属区域的运行而存在,结束而释放


匿名对象。


匿名对象使用方式一:当对对象的方法只调用一次时,可以用匿名对象来完成,这样写比较简化。如果对一个对象进行多个成员调用,必须给这个对象起个名字。

匿名对象使用方式二:可以将匿名对象作为实际参数进行传递。

书写格式例如:new Student().toString();


面向对象:三个特征:封装,继承,多态。


封装:

封装是指隐藏对象的属性和实现细节,仅对外提供公共的访问方式。

好处: 1将变化隔离 2便于使用3 提高重用性4提高安全性


private int age;//私有的访问权限最低,只有在本类中的访问有效。

注意:私有仅仅是封装的一种体现形式而已。

私有的成员:其他类不能直接创建对象访问,所以只有通过本类对外提供具体的访问方式来完成对私有的访问,可以通过对外提供函数的形式对其进行访问。


好处:可以在函数中加入逻辑判断等操作,对数据进行判断等操作。


总结:开发时,记住,属性是用于存储数据的,直接被访问,容易出现安全隐患,所以,类中的属性通常被私有化,并对外提供公共的访问方法。

这个方法一般有两个,规范写法:对于属性 xxx,可以使用setXXX(),getXXX()对其进行操作。


构造函数:


构造函数函数名和类名相同。2不用定义返回值类型。3不可以写ruturn语句。

 构造函数的作用:可以用于给对象进行初始化。

因此所有对象创建时,都需要初始化才可以使用。


构造函数和一般函数有什么区别呢?

1:两个函数定义格式不同。

2:构造函数是在对象创建时,就被调用,用于初始化,而且初始化动作只执行一次。

   一般函数,是对象创建后,需要调用才执行,可以被调用多次。


什么时候使用构造函数呢

分析事物时,发现具体事物一出现,就具备了一些特征,那就将这些特征定义到构造函数内。


构造代码块

给对象进行初始化。对象一建立就运行,而且优先于构造函数运行。


构造代码块和构造函数的区别:

   构造代码块是给所有对象进行统一初始化,

   而构造函数是给对应的对象初始化。

this:代表对象。就是所在函数所属对象的引用。

this到底代表什么呢?

哪个对象调用了this所在的函数,this就代表哪个对象,就是哪个对象的引用。


开发时,什么时候使用this呢?

在定义功能时,如果该功能内部使用到了调用该功能的对象,这时就用this来表示这个对象。

this还可以用于构造函数间的调用。

调用格式:this(实际参数)

this对象后面跟上调用的是成员属性和成员方法(一般方法)

this对象后面跟上 ()调用的是本类中的对应参数的构造函数。


注意:用this调用构造函数,必须定义在构造函数的第一行。因为构造函数是用于初始化的,所以初始化动作一定要执行。否则编译失败。


package pract;

public class Student {
	private String name;//成员变量
	private int age;//private 私有权限修饰,需要对外提供公共的访问方法。
	
	{//构造代码块:用于给所有对象初始化
		System.out.println("学习");
	}
	
	
	public Student() {
		super();
	}
	public Student(String name, int age) {//构造函数,给对应对象初始化
		this();// 调用的是本类中的对应参数的构造函数。
		this.name = name;//this用于构造函数内,调用的是成员属性name;
		this.age = age;
	}
	public String getName() {//获取对象姓名的方法;
		return name;
	}
	public void setName(String name) {//设置对象姓名的方法或者修改;
		this.name = name;
	}
	public int getAge() {//获取对象年龄的方法;
		return age;
	}
	public void setAge(int age) {///设置对象年龄的方法或者修改;
		this.age = age;
	}
	
	
	public String toString() {//返回值为String的一个方法;此方法是返回对象的姓名年龄。
		return "Student [name=" + name + ", age=" + age + "]";
	}
	public static void main(String[] args) {
		Student s = new Student("liming",12);//名字为s的学生类对象
		System.out.println(s.toString());
		
		System.out.println(new Student("zhangsan",22).toString());//匿名对象
	}
	/*程序输出结果如下:
	 * 学习
	 *Student [name=liming, age=12]
	 *学习
	 *Student [name=zhangsan, age=22]
	 * 
	 * */

}

static


特点:

1,想要实现对象中的共性数据的对象共享。可以将这个数据进行静态修饰。

2,被静态修饰的成员,可以直接被类名所调用。也就是说,静态的成员多了一种调用方式。类名.静态方式。

3,静态随着类的加载而加载。而且优先于对象存在。


弊端:

1,有些数据是对象特有的数据,是不可以被静态修饰的。因为那样的话,特有数据会变成对象的共享数据。这样对事物的描述就出了问题。所以,在定义静态时,必须要明确,这个数据是否是被对象所共享的。

2,静态方法只能访问静态成员,不可以访问非静态成员。

因为静态方法加载时,优先于对象存在,所以没有办法访问对象中的成员。

3,静态方法中不能使用thissuper关键字。

因为this代表对象,而静态在时,有可能没有对象,所以this无法使用。

4,主函数是静态的。


什么时候定义静态成员呢?或者说:定义成员时,到底需不需要被静态修饰呢?

成员分两种:

1,成员变量。(数据共享时静态化)

该成员变量的数据是否是所有对象都一样:

如果是,那么该变量需要被静态修饰,因为是共享的数据。

如果不是,那么就说这是对象的特有数据,要存储到对象中。

2,成员函数。(方法中没有调用特有数据时就定义成静态)

   如果判断成员函数是否需要被静态修饰呢?

   只要参考,该函数内是否访问了对象中的特有数据:

   如果有访问特有数据,那方法不能被静态修饰。

   如果没有访问过特有数据,那么这个方法需要被静态修饰。


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

1,成员变量所属于对象。所以也称为实例变量。

静态变量所属于类。所以也称为类变量。

2,成员变量存在于堆内存中。

静态变量存在于方法区中。

3,成员变量随着对象创建而存在。随着对象被回收而消失。

静态变量随着类的加载而存在。随着类的消失而消失。

4,成员变量只能被对象所调用 。

静态变量可以被对象调用,也可以被类名调用。

所以,成员变量可以称为对象的特有数据,静态变量称为对象的共享数据。


静态的注意:静态的生命周期很长。

静态代码块:就是一个有静态关键字标示的一个代码块区域。定义在类中。

作用:可以完成类的初始化。静态代码块随着类的加载而执行,而且只执行一次(new多个对象就只执行一次)。如果和主函数在同一类中,优先于主函数执行。


Public:访问权限最大。

static:不需要对象,直接类名即可。

void:主函数没有返回值。

Main:主函数特定的名称。

(String[]args):主函数的参数,是一个字符串数组类型的参数,jvm调用main方法时,传递的实际参数是 new String[0]

jvm默认传递的是长度为0的字符串数组,我们在运行该类时,也可以指定具体的参数进行传递。可以在控制台,运行该类时,在后面加入参数。参数之间通过空格隔开。jvm会自动将这些字符串参数作为args数组中的元素,进行存储。

package pract;

class StaticCode{
	final static int num = 9;//静态变量也是类变量

	static{//静态代码块 
		System.out.println("a");
	}
	
	StaticCode(){//无参数构造函数
		System.out.println("b");
	}
	
	{//构造代码块
		System.out.println("c"+num);//调用静态不用this
	}
	

	StaticCode(int x){//有参数构造函数
		
		System.out.println("d");
	}
	public static void show(){//show方法
		
		System.out.println("show run");
	}
}

public class StaticCodeDemo {
		static{//staticCodeDemo的静态代码块
			System.out.println("e");
		}
		public static void main(String[] args) {
			new StaticCode();// e a c9 b ;
			new StaticCode(4);//e  a c9  d;
			//静态代码块、构造代码块、构造函数同时存在时的执行顺序:静态代码块 ,构造代码块 , 构造函数;
		}

}

单例设计模式保证一个类在内存中的对象唯一性。

package pract;


public class SJMS {
	/*如何保证对象唯一性呢?
 	思路:
	1,不让其他程序创建该类对象。
	2,在本类中创建一个本类对象。
	3,对外提供方法,让其他程序获取这个对象。

	步骤:
	1,因为创建对象都需要构造函数初始化,只要将本类中的构造函数私有化,其他程序就无法再创建该类对象;
	2,就在类中创建一个本类的对象;
	3,定义一个方法,返回该对象,让其他程序可以通过方法就得到本类对象。(作用:可控)
 */
		// 恶汉式
	private SJMS(){}
	private static SJMS sjms = new SJMS();
	public static SJMS getInstance(){
		return sjms;
	}
}
class SJMS2{
	private SJMS2(){}//懒汉式
	private static SJMS2 sjms2 = null;
	public static SJMS2 getInstance(){
		if(sjms2==null){
			sjms2 = new SJMS2();
		}
		return sjms2;
	}
}

继承特点:

1,提高了代码的复用性。

2,让类与类之间产生了关系。有了这个关系,才有了多态的特性。


Java语言中:java只支持单继承,不支持多继承。

1,因为多继承容易带来安全隐患:当多个父类中定义了相同功能,当功能内 容不同时,子类对象不确定要运行哪一个。

2,但是java保留这种机制。并用另一种体现形式来完成表示。多实现。

,3ava支持多层继承。也就是一个继承体系(爷爷父亲子)。


如何使用一个继承体系中的功能?

想要使用体系,先查阅体系父类的描述,因为父类中定义的是该体系中共性功能。通过了解共性功能,就可以知道该体系的基本功能。


那么在具体调用时,要创建最子类的对象,为什么呢?

1,是因为有可能父类不能创建对象,

,2,是创建子类对象可以使用更多的功  能,包括基本的也包括特有的。


如果子类中出现非私有的同名成员变量时,

1,子类要访问本类中的变量,用thisthis代表的是本类对象的引用。

,  2子类要访问父类中的同名变量,用supersuper代表的是父类对象的引用。


当子类出现和父类一模一样的函数时,会发生覆盖。

1,子类覆盖父类,必须保证子类权限大于等于父类权限,才可以覆盖,否  则编译失败。

2,静态只能覆盖静态。


重载:只看同名函数的参数列表。

重写:子父类方法要一模一样。


super调用一般函数是super.方法,调用构造函数是super()

当父类中没有空参数的构造函数时,子类必须手动通过super语句形式来指定要访问父类中的构造函数。

当然:子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。子类中至少会有一个构造函数会访问父类中的构造函数。


final最终是一个修饰符

 1,可以修饰类,函数,变量。

 2,被final修饰的类不可以被继承。为了避免被继承,被子类复写功能。

 3,被final修饰的方法不可以被复写。

  4,被final修饰的变量是一个常量只能赋值一次,既可以修饰成员变量,有可以修饰局部变量。

 5作为常量:常量的书写规范所有字母都大写,如果由多个单词组成。单词间通过_连接。

package pract;

class Fu{
	public static final double PI = 3.14;

	public Fu() {
		super();//这是调用Object的构造函数,因为Object是所有class的父类
		System.out.println("这是Fu类"+PI);
	}
	public  void  show(){
		System.out.println("这是父类的show方法");
	}
}

class Zi extends Fu{

	public Zi() {
		super();
		// super() 调用Fu类的构造函数
		System.out.println("这是zi类"+PI);//调用父类的PI
	}
	public  void  show(){	//覆盖父类中的show方法
		System.out.println("这是子类的show方法");
	}
		
}

public class ExtendsDemo {
	public static void main(String[] args) {
		 new Zi().show();//匿名对象
		 /*程序运行结果如下:
		  	这是Fu类3.14
			这是zi类3.14
			这是子类的show方法	
		  */
 
	}

}

抽象类:abstract

在不断抽取过程中,将共性内容中的方法声明抽取,但是方法不一样,没有抽取,这时抽取到的方法,并不具体,需要被指定关键字abstract所标示,声明为抽象方法。

抽象方法所在类一定要标示为抽象类,也就是说该类需要被abstract关键字所修饰。


抽象类的特点:

1,抽象方法一定在抽象类中。

2,抽象方法和抽象类都必须被abstract关键字修饰。

3,抽象类不可以用new创建对象。因为调用抽象方法没意义。

4,抽象类中的抽象方法要被使用,必须由子类复写起所有的抽象方法后,建立子类对象调用。

   如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。


抽象类的细节:

1:抽象类中是否有构造函数?有,用于给子类对象进行初始化。

2:抽象类中是否可以定义非抽象方法?

   可以。抽象类在描述事物时,有些功能不具体。所以抽象类和一般类在定义上,都是需要定义属性和行为的。只不过,比一般类多了一个抽象函数。而且比一般类少了一个创建对象的部分。

3:抽象关键字abstract和哪些不可以共存?final , private , static

4:抽象类中可不可以不定义抽象方法?可以。抽象方法目的仅仅为了不让该类创建对象。

abstract class Student//一个抽象的Student类
{
	abstract final void study();//抽象的study方法,需要被子类实现。
	void sleep()//抽象类中可以定义非抽象方法。
	{
		System.out.println("躺着");
	}
}

模板方法设计模式

/*
需求:获取一段程序运行的时间。
原理:获取程序开始和结束的时间并相减即可。

获取时间:System.currentTimeMillis();

*/

abstract class GetTime
{
	public final void getTime()
	{
		long start = System.currentTimeMillis();//程序开始的时间

		runcode();//这个模式是模板方法设计模式
		/*
		什么是模版方法呢?
		在定义功能时,功能的一部分是确定的,但是有一部分是不确定,而确定的部分在使用不确定的部分,
		那么这时就将不确定的部分暴露出去。由该类的子类去完成。
		*/

		long end = System.currentTimeMillis();//程序结束的时间

		System.out.println("毫秒:"+(end-start));//计算出程序运行的时间
	}
	public abstract void runcode();//模板方法,吧不确定的程序暴露出去

}


class SubTime extends GetTime
{

	public void runcode()//继承GetTime类,实现不确定的程序
	{
		
		for(int x=0; x<4000; x++)
		{
			System.out.print(x);
		}
	}
}


public class  TemplateDemo
{
	public static void main(String[] args) 
	{
		SubTime gt = new SubTime();//建立子类对象
		gt.getTime();//获取程序运行时间
	}
}

interface用于定义接口

 1,接口中常见定义:常量,抽象方法。

 2,接口中的成员都有固定修饰符。

      常量:publicstatic final         

      方法:publicabstract


3:接口中有抽象方法,说明接口不可以实例化。接口的子类必须实现了接口中所有的抽象方法后,该子类才可以实例化。否则,该子类还是一个抽象类。

4:类与类之间存在着继承关系,类与接口中间存在的是实现关系。

   继承用extends ;实现用implements

5:接口和类不一样的地方,就是,接口可以被多实现,这就是多继承改良后的结果。

class Test extends Demo implements Inter,InterA


6:一个类在继承另一个类的同时,还可以实现多个接口。所以接口的出现避免了单继承的局限性。还可以将类进行功能的扩展。

7:其实java中是有多继承的。接口与接口之间存在着继承关系,接口可以多继承接口。


接口都用于设计上,设计上的特点:(可以理解主板上提供的接口)

1:接口是对外提供的规则。

2:接口是功能的扩展。

3:接口的出现降低了耦合性。


抽象类与接口:

抽象类:一般用于描述一个体系单元,将一组共性内容进行抽取,特点:可以在类中定义抽象内容让子类实现,可以定义非抽象内容让子类直接使用。它里面定义的都是一些体系中的基本内容。

接口:一般用于定义对象的扩展功能,是在继承之外还需这个对象具备的一些功能。

抽象类和接口的共性:都是不断向上抽取的结果。


抽象类和接口的区别:

1:抽象类只能被继承,而且只能单继承。

接口需要被实现,而且可以多实现。

2:抽象类中可以定义非抽象方法,子类可以直接继承使用。

接口中都有抽象方法,需要子类去实现。

3:抽象类使用的是 is a关系。

接口使用的 like a关系。

4:抽象类的成员修饰符可以自定义。

接口中的成员修饰符是固定的。全都是public的。

package pract;


abstract class animal{//抽象类
	abstract void eat();
	abstract void sleep();
}
interface living//接口
{
	void live();
}
public class Dog extends animal implements living {
	public void eat(){//覆盖abstract 类 的eat方法
		System.out.println("吃骨头");
	}
	public void sleep(){//覆盖abstract类的sleep方法
		System.out.println("趴着睡");
	}
	public void live(){//实现接口的live方法
		System.out.println("生活在陆地上");
	}

	public static void main(String[] args) {
		// 创建Dog对象,调用Dog方法
		Dog d = new Dog();
		d.eat();
		d.sleep();
		d.live();
	}

}

 



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值