NO7.java学习笔记【面向对象、栈内存、堆内存、构造函数、this、super、继承、覆盖、对象实例化、final】

一、理解面向对象:

面向过程:强调的是功能行为。

面向对象:将功能封装进对象,强调具备了功能的对象。

面向对象是基于面向过程的。

二、JAVA把内存分为两种:栈内存和堆内存。

//在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配。当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的作用域后,java会自动释放掉为该变量分配的内存空间,该内存空间可以立刻被另作他用。
//堆内存用于存放由new创建的对象和数组
在堆中分配的内存,由java虚拟机自动垃圾回收器来管理。在堆中产生了一个数组或者对象后,还可以在栈中定义一个特殊的变量,这个变量的取值等于数组或者对象在堆内存中的首地址,在栈中的这个特殊的变量就变成了数组或者对象的引用变量,以后就可以在程序中使用栈内存中的引用变量来访问堆中的数组或者对象,引用变量相当于为数组或者对象起的一个别名,或者代号。
引用变量是普通变量,定义时在栈中分配内存,引用变量在程序运行到作用域外释放。而数组&对象本身在堆中分配,即使程序运行到使用new产生数组和对象的语句所在地代码块之外,数组和对象本身占用的堆内存也不会被释放,数组和对象在没有引用变量指向它的时候,才变成垃圾,不能再被使用,但是仍然占着内存,在随后的一个不确定的时间被垃圾回收器释放掉。这个也是java比较占内存的主要原因,实际上,栈中的变量指向堆内存中的变量,这就是 Java 中的指针!

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

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

好处:将变化隔离;便于使用;提高重用性;挺高安全性。

封装原则:将不需要对外提供的内容隐藏起来;把属性都隐藏,提供公共方法对其访问。

四、构造函数

特点:函数名与类名一样,不用定义返回值,不可以定义return语句。

作用:对对象进行初始化。

当在类中没有定义构造函数时,那么系统会使用默认的构造函数对对象进行初始化,当定义的构造函数,则再要使用默认的构造函数则会报错。

五、this

	Person(String name,int age)
	{
		this.name=name;
		this.age=age;
		/*
		Java提供了一个this关键字,this关键字总是指向调用该方法的对象。
		构造器中引用该构造器正在初始化的对象。
		在方法中引用调用该方法的对象。
		*/
	}

class Person
{
	String name;//成员变量,实例变量
	/*
	static特点:
	1.随着类的加载而加载,也就是说:静态会随着类的消失而消失。
	  说明它的生命周期最长。
	2.优先于对象存在。静态是先存在的,对象是后存在。
	3.被所有对象共享。
	4.可以直接被类名调用。

	实例变量和类变量的区别:
	1.存放位置:类变量随着类的加载而存在于方法区中。
	  实例变量随着对象的建立而存在于堆内存中。
	2.生命周期:
	  类变量生命周期最长,随着类的消失而消失。
	  实例变量的生命周期,随着对象的消失而消失。
	 
	静态使用注意事项:
	1.静态方法只能访问静态成员。
	  非静态方法既可以访问静态也可以访问非静态
	2.静态方法中不可以定义this,super关键字
	  因为静态优先于对象存在,所以静态方法中不可以出现this。
	3.主函数是静态的。

	静态有利有弊:
	利:对对象的共享共享数据进行单独空间的存储,节省内存空间。没有必要每个对象中存储一份。
	    可以直接被类名调用。
	弊:生命周期过长。
	    访问出现局限性。(静态虽好,只能访问静态)
	*/
	static String country = "CN";//静态的成员变量,类变量。
	public void show()
}
class StaticDemo 
{
	public static void main(String[] args) 
	{
		System.out.println("Hello World!");
	}
}
六、继承
1、继承的好处:
1.提高了代码的复用性。2.让类与类之间产生关系,给第三个特征多态提供了前提。
注意:java中支持单继承(),不直接支持多继承,但对C++中的多继承机制进行改良。
             单继承:一个子类只能有一个直接父类。
             多继承:一个子类可以有多个直接父类(java中不允许,进行改良)。不直接支持,因为多个父类中有相同的成员,会产生调用的不确定性。

在java中是通过"多实现"的方式来体现的。

java支持多层(多重)继承;
class C extends B; 
class B extends A;
继承体系。
当要使用一个继承体系时,
1.查看该体系的顶层类,了解该体系的基本功能。
2.创建体系中的最子类对象,完成功能的使用。
2、什么时候定义继承?
当类与类中存在着所属的关系的时候,就定义继承。A是B中的一种,A extens B.
当本类的成员和局部变量同名用this区分
当子父类的成员变量同名时用super区分父类。
3、this和super的用法很相似:
this:代表一个本类对象的引用。
super:代表一个父类所属空间。
4、子类对象不具备父类的私有成员。
成员函数:当子父类中出现成员函数一模一样的情况,会运行子类的函数。
这种现象,称为覆盖操作。这时函数在子父类中的特性。
5、函数两个特性:1、重载。同一个类中的构造函数,函数名一样,参数列表不一样。2、覆盖。子类中,覆盖也称为重写,覆写。override
5.1覆盖注意事项:
1.子类方法覆盖父类方法时,子类权限必须要大于等于父类的权限。
2.静态只能覆盖静态,或被静态覆盖。
5.2使用覆盖操作:
当一个类进行子类的扩展时,子类需要保留父类的功能声明。
但是要定义子类中该功能的特有内容,就使用覆盖操作完成。

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

子类中所有的构造函数默认都会访问父类中的默认构造函数。

为什么子类实例化的时候要访问父类的构造函数?

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

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

子类的实例化过程:子类中所有的构造函数默认都会访问父类中的默认构造函数。

为什么子类实例化的时候要访问父类的构造函数?
那是因为子类继承了父类,获取到了父类中的内容(属性),所以在使用父类的内容之前,
要先看父类是如何对自己的内容进行初始化的。
所以子类在构造对对象时,必须访问父类中的构造函数。
为了完成这个必须的动作,就在子类的构造函数中加入super()语句。

如果父类中没有定义空参数构造函数,那么子类的构造函数必须用super明确调用
父类哪个构造函数。同时子类的构造函数中如果使用了this调用了本类构造函数时,
那么super就没有了,因为super和this都只能定义在第一行,所以只能有一个。
但是可以保证的是,子类中肯定有其他的构造函数访问父类的构造函数。

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

Object类是根类是所有类的父类或者间接父类。

构造器先忙完父类的事情,在忙自己的事情。
*/

class Fu
{
	/*
	int num;
	Fu()
	{
		num=10;
		System.out.println("AA Fu run");
	}
	Fu(int x)
	{
		System.out.println("B Fu run:"+x);
	}
	*/
	Fu()
	{
		super();
		show();
		return;
	}
	void show()
	{
		System.out.println("fu show");
	}
}
class Zi extends Fu
{
	int num=8;
	Zi()
	{
		//super();调用的就是父类中的空参数构造函数。
		//
		//this();出现递归
		//System.out.println("C Zi run:");
		super();
		System.out.println("num="+num);
		return;
	}
	void show()
	{
		System.out.println("Zi show....."+num);
	}
	/*
	Zi(int x)
	{
		//super(x);
		//super();隐式函数
		this();
		System.out.println("D Zi run:"+x);
	}
	*/
}
class ExtendsDemo5
{
	public static void main(String[] args) 
	{
		Zi z = new Zi();
		z.show();
	}
}
/*
一个对象实例化过程:
Person p = new Person();
1.JVM会读取指定路径下Person.class文件,并加载进内存,
   并会先加载Person的父类(如果有直接父类的情况下)。
2.在堆存中开辟空间,分配内存地址。
3.并在对象空间中,对对象中的数值进行默认初始化。
4.调用对应的构造函数进行初始化。
5.在构造函数中,第一行会先调用父类中构造函数进行初始化。
6.父类初始化完毕后,在对子类的属性进行显示初始化。
7.在进行子类构造函数的特定初始化。
8.初始化完毕后,将地址值赋值给引用变量。


*/

class Demo
{
	Person p = new Person();
}
继承弊端:打破了封装性。
final关键字:

1、final是一个修饰符,可以修饰类,方法,变量。
2、final修饰的类不可以被继承。
3、final修饰的方法不可以被覆盖。
4、final修饰的变量是一个常量(大写字字母),只能赋值一次。
写法规范:常量所有字母都大写,多个单词,中间使用下划线连接。

class Fu
{
	private void method()
	{
		//调用了底层系统的资源
	}
}
class Zi extends Fu
{
	final int a=10;
	void method()
	{
		final int x = 9;
		final int y;
		System.out.println(x);
	}
}
class finalDemo
{
	public static void main(String[] args) 
	{
		Zi z = new Zi();
		z.method();
		System.out.println("Hello World!");
	}
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值