黑马程序员-java面向对象1

------- android培训java培训、期待与您交流! ----------

面向对象1

面向对象笔记是我后来加的,笔记整理后发现少了面向对象这一块,自我感觉面向对象掌握的还好,毕竟看了两遍,想想看还是把这块笔记加上,算是查落补缺吧,面向对象笔记分为三部分

1.什么是面向对象
在java中有句话,"一切都是对象",java语言假设我们只进行面向对象的程序设计,也就是说,在开始用java设计之前必须将思想转换到面向对象的世界中来,这算是基本功了
可以使你具备使用这样一种编程语言编程的能力,这种语言学起来很简单比其他的面向对象的语言要更加的好用(特别是C++)

2.如何操纵对象
C和C++是使用指针来操纵对象,这在java当中得到了简化,一切都可以被视为对象,所以可以采用固定的语法,尽管一切都可以看做是一个对象,但操纵的标示实际上是一个对象
的引用,你可以将他看出遥控器(引用)和电视机(对象),只要握住这个遥控器就可以处理电视中的信息,遥控器可以脱离电视机独子存在,也就是说,你可以拥有一个引用,但是
不一定需要有一个对象与其相关联
例如 String s;
这里只有一个引用,没有对象和其关联,这时候如果调用s.toString()方法,会抛出一个空指针异常,如果 String s = "abc",这个对象就初始化了,String这种初始化是java语言的
一种特性,通常必须对对象采用一种更通用的一种初始化方法


3.如何创建对象
在java中,我们可以使用new关键字创建一个对象
前面的例子可以改为 String s = new String("abc"); java中除了 String 之外,还有很多乱七八糟的类型.


4.内存分配
程序运行后,就要为各种引用变量和对象分配内存,有五个地方可以存储数据
1.寄存器:这是最快的存储区域,位于处理器内部,但是寄存器的数量相当有限,寄存器会根据需求来分配,不能直接控制,也不能感觉到它存在的任何迹象
2.栈内存:在java中,一般对象的引用以及一些基础数据类型装在栈内存当中,栈指针向下移动,分配新的内存,向上移动,释放内存
3.堆内存:一个通用的内存池,用于存放所有的java对象,但是释放对象时,没有栈内存效率那么高,得找java特有的垃圾收集器回收对象
4.常量存储:在java中使用static关键字修饰的字段和变量有一个专用的常量池来存储他们
5.非RAM存储:如果程序存活于程序之外,他可以不受程序流程的控制存活于程序之外,例如IO流中有个类可以将对象写入本地硬盘中去


5.对象的销毁

在java中,永远不需要考虑销毁数据,包括对象和引用,下面通过一段代码来看数据的生命周期

	public static void main(String[] args) {
		int b = 98;
		{
			int a = 97;
			String str = new String("abc");
			System.out.println(a);
			System.out.println(b);
		}
		//出了上面这个大括号之后,a变量就被释放了,str这个引用也已经被释放了,但是对象还在内存中,可以存活于作用域之外
		//System.out.println(str);
	}
对象和基础数据类型以及对象的引用不同,对象出了大括号可能继续存在,但是去失去了对象的引用,java中将失去引用的对象视为垃圾对象,等待垃圾回收器回收

6.创建自己的数据类型 --类
如果一切都是对象,那么用什么来产生一个对象呢,java中使用class这个关键字来声明一个类
例如: class A{


 }
我申明了一个类A,之后就可以使用这个类来创建对象 new A();
但是一个类不可能会这么简单,里面可能会有字段和方法,你如果想要运行的话,还必须要有main()方法
例如

	class A{
		int a=1;
		boolean b;
		String str;
		void printData() {
			System.out.println(a);
		}
		public static void main(String[] args) {
			printData();
		}
		public int getLength(String s) {
			return s.length();
		}
	}
在这个类中,有属于他自己的字段,方法,字段可以是基本数据类型,也可能是另外一个类的对象,在这个例子中有的字段我赋予了他初值,有的没有,没给初始值的,java
会给他衣蛾默认值,引用型变量就是null
字段说完就是方法了,在这个程序中有两个方法
1. void printData() {
System.out.println(a);
}
方法名为printData,void代表的意思是该方法没有任何返回值,千万不要认为返回的是一个void的值,该方法没有方法参数
2. public static void main(String[] args) {
printData();
}
方法名为 main(),自己定义方法名和字段名时,尽量(除了主方法,绝对不要使用main)不要使用main,main方法又叫做主函数方法,程序运行后
就是执行main方法体中的代码块main()方法的void的前面还加了public static 两个修饰符,public的意思是公共的,代表此方法可以可以再任何地方被调用访问,
static 静态修饰符,代表该方法可以创建本类的对象而直接通过 类名.方法名调用,这个也很好理解,程序运行后,没有任何对象,自然不可能通过对象.方法名调用方法了,
这时候就必须要有一个主方法,当本类的字节码文件加载进内存后,jvm(java虚拟机)调用main()方法运行程序,自然不需要什么对象了,main方法可以接受一个方法参数,
接受的是String类对象的数组
public static void main(String[] args)这个地方一个都不能改要不然jvm就找不到运行的入口了
3.  public int getlength(String s) {
return s.length();
}
这个方法返回的是一个基础数据类型int值,该值是你传入方法中String对象参数的长度,这里又使用到了一个关键字return,这个关键字有两个作用,1.方法执行后返回一个值,
返回具体数值的类型必须与你定义的方法名前面的返回值一致,否则连编译都无法通过,2.return 的第二个作用就是退出方法,return语句后面的话,永远都得不到执行,在用void
修饰的方法中可以有 return 语句,该语句的作用就是退出当前方法

7.利用构造方法初始化数据
什么是构造方法?
当你使用new关键字创建一个对象时,就调用了一次构造方法,在上例中在类中虽然并没有构造方法,但是java会给你生成一个默认的无参的构造方法,就是
class A{


}类的前面如果有修饰符的话,默认构造方法前面也会有修饰符
构造方法是我们用来创建对象的,创建对象之后就要进行字段(也可以叫成员变量)的初始化了,如果我们能在创建对象的时候同时进行初始化这就太好了这时候我们就可以在构造方法中写一些赋值语句用来初始化成员变量
例如

class Person{
	String name;
	int age;
	//构造方法的重载
	public Person(String name, int age) {
		this();
		this.name = name;
		this.age = age;
	}
	public Person() {
		
	}
}

这个Person类中,我自己定义了一个构造方法,自己定义后,系统将不会再帮你生成一个无参的构造方法,如果你使用无参的构造方法创建对象,编译将出错,在这里我们又接触到了
一个关键字就是 this ,this代表当前对象,在上面这个程序的构造方法中,局部变量和成员变量重名了,如果不加this的话,jvm搞不清楚谁是谁,加了this,则代表this.name这个name
是成员变量,this关键字的作用不止于此,当用到构造方法的重复调用时,就是在一个构造方法中调用另外一个构造方法时就可以使用this(参数列表),但是这句代码必须写在构造方法
的第一行,还有一点就是 this 这个关键字不要出现在静态代码块中, this 代表的是对象本身,是基于对象创建后的,而静态代码块和静态方法是未创建对象时调用的
关于构造方法还有一点没讲的是构造方法前面的修饰符,public 是最大的权限修饰符,修饰符有很多,并不是很难理解,我会在后面的笔记中对其进行讨论,这里暂且略过.


8.方法重载
既然有构造方法的重载,那么就会有普通方法的重载,所谓的重载就是指方法名相同,参数列表不同,参数列表的不同包括参数个数和参数类型,千万不要认为返回值不同,
方法名和参数列表相同,也属于重载,一个对象去调用一个方法时,会根据参数列表的异同判断到底使用哪个方法,如果一个子类继承父类的话,父类和子类的方法可能出现重载,
如果方法名和参数类型相同,就是覆写,这在后面的笔记会写到


9构造器的初始化顺序
你使用一个类的构造方法创建一个对象,是不是构造方法立即得到执行了呢,在这之前需要干什么事呢,看下面一段实例代码
例如

public class Test {
	public static int count = 1;
	public static void main(String[] args) {
		new Person().print();
	}
	public Test() {
		System.out.println("Test构造方法得到执行" + count + "次");
		count++;
	}
 
}

class Person{
	Test test1 = new Test();
	public Person() {
		System.out.println("Person构造方法得到执行");
	}
	Test test2 = new Test();
	public void print() {
		System.out.println("print方法得到执行");
	}
	{
		test2 = new Test();
		System.out.println("构造代码块得以执行");
	}
} 

这个程序运行的结果是
Test构造方法得到执行1次
Test构造方法得到执行2次
Test构造方法得到执行3次
构造代码块得以执行
Person构造方法得到执行
print方法得到执行


由这个打印数据我们来分析对象的初始化过程,1.程序进入main方法,创建Person对象,调用构造方法,2.调用构造方法之前必须先初始化成员变量,Person类中有两个成员变量
这两个成员变量都是Test类的对象,这时候就必须调用Test的构造方法,两个Test对象初始化完毕之后.3.调用构造方法,但在调用构造方法之前,如果有构造代码块的话,会先执行
构造代码块,构造代码块虽然不在构造方法内部,但他好像和构造方法绑定在一起了,构造方法执行几次,构造代码块就会执行几次,并且优先于构造方法执行4.构造代码块执行后
构造方法才得以执行.5.调用Person对象的print()方法


10.静态数据的初始化
静态数据包括静态变量,静态代码块,静态方法(方法不管是静态还是非静态,不被调用,就得不到执行,main方法除外,main方法是jvm调用),静态数据是属于字节码文件的,不属于对象
你就算创建无数个对象字节码文件只有一份,所以静态数据只有一份.静态代码块执行一次,静态成员变量初始化一次,就是在类加载器将本地硬盘上的编译好的.class文件加载进内存变成字节码文件时执行,什么是类加载器我在后面的有关于反射的笔记中已经写到.
稍微修改一下上面的程序代码,让我来看一下静态数据的初始化
例如

public class Test {
	public static int count = 1;
	static Person p = new Person();
	static {
		System.out.println("Test静态代码块执行");
	}
	public static void main(String[] args) {
		
	}
	public Test() {
		System.out.println("Test构造方法得到执行" + count + "次");
		count++;
	}
 
}

class Person{
	static {
		System.out.println("Person静态代码块执行");
	}
	static Test t = new Test(); 
	public Person() {
		System.out.println("Person构造方法得到执行");
	}
	public void print() {
		System.out.println("print方法得到执行");
	}
	{
		System.out.println("Person构造代码块得以执行");
	}
} 

 打印的结果
Person静态代码块执行
Test构造方法得到执行1次
Person构造代码块得以执行
Person构造方法得到执行
Test静态代码块执行


分析初始化过程:在主函数main()方法中我什么都没写但是程序还是打印了一些数据,这些数据就是随着字节码文件加载进内存而执行和初始化的1.首先初始化的是静态成员变量p
创建p的对象又需要 Person 类的字节码文件,这时候就要去加载 Person 类的字节码文件,同时初始化Person中的静态数据,所以第一个打印的是"Person静态代码块执行"2.Person类接下来做的事就是初始化静态成员变量,静态成员变量t是Test的对象,Test字节码文件已经加载进内存了,所以静态数据不会再得到执行,直接执行构造方法.3.在后面就简单了,Person构造方法得到执行,执行前,构造代码块执行.还有注意一点,就是静态代码块和静态成员变量的初始化,究竟谁排在前面,优先级都是一样的,谁位于代码的上面,谁先执行.切记切记.


11修饰符总结
修饰符包括权限访问权限修饰符,静态数据修饰符,最终修饰符,同步修饰符
访问权限修饰符,看下面一张表
                 本类      同一包中          子类        任何类中
public        ok              ok                  ok            ok
protected  ok              ok                  ok
default       ok              ok
private       ok
权限修饰符可以用来修饰类,构造方法,成员变量,成员方法

修饰类的修饰符只能是 public 或 default ,只有当这个类位于别的类内部,成为一个内部类的时候,4个访问权限修饰符才都能修饰他,内部类我以后的笔记会对他进行讨论

static 静态数据修饰符,是属于类的,只有一份

final 最终修饰符,被 final 修饰的类无法被继承(面向对象的高级部分),被 final 修饰的变量无法改变其值,值得注意的是,被 final 修饰的变量如果是基础数据类型的话,其值
无法改变,如果是引用型数据的话,包括对象和数组,是指其引用不能变,对象可以变化.被 final 修饰的方法无法被子类所覆盖,是最终方法.
abstract 用 abstract 修饰的类叫做抽象类,抽象类无法创建对象,但是可以有自己的构造方法,抽象方法只有方法的声明,没有具体的实现,是用来被子类覆写的,具体等到抽象类时再说
synchronized 用 synchronized 方法视为同步的方法,主要用在多线程处理共享数据中,到线程那一章在说吧


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值