目录
一、面向对象基本概念
1、什么是面向对象:
2、建立面向对象思维方式
二、类与对象
1、什么是类
2、类与对象的关系
3、类和对象的定义格式
4、类与对象的内存详解
三、面向对象封装性
1、封装性的概念
2、封装的好处
3、成员变量和局部变量
i、在类中的位置不同
ii、在内存中的位置不同
iii、生命周期不同
iv、初始化值不同
4、构造方法
i、什么是构造方法?
ii、构造方法的定义
iii、构造方法小结
四、this关键字、值传递与引用传递
1、this关键字
2、值传递
3、引用传递
4、String类型传递
面向对象是一种编程思想。
面向对象是一种思考问题的思维方式
先整体,再局部
先抽象,再具体
能做什么,再怎么做
类:分类、分别;
通过分类,我们可以区别不同的事物种类;
所以,类是一组具有相同特性(属性)与行为(方法)的事物集合;
类表示一个共性的产物,是一个综合的特征,而对象,是一个个性的产物,是一个个体的特征。
类由属性和方法组成:
属性:就相当于一个个的特征
方法:相当于人的一个个的行为,例如:说话、吃饭、唱歌、睡觉;
在java中可以使用以下的语句定义一个类:
class 类名称{
属性名称;
返回值类型 方法名称(){};
}
对象的定义:
一个类要想真正的进行操作,则必须依靠对象,对象的定义格式如下:
类名称 对象名称 = new 类名称();
如果想要访问类中的属性和方法(方法的定义),可以依靠下面的语法形式
访问类中的属性:
对象.属性;
访问类中的方法:
对象.方法();
public class Test{ public static void main(String[] args){ //用下面的类,首先要声明 Horse h = null; //声明一个类的变量(除了八种基本数据类型以外,都是引用数据类型,包括数组) // 创建一个Hoses类型的对象,实例化对象 h = new Horse() // 有了对象, 我们就可以调用对象的属性和方法 h.name = "赤兔马"; h.age = 350; // 调用对象的方法 h.run(); // 调用方法,方法就会被执行 h.eat(); // 匿名对象 new Horse().eat();//只能使用一次,用完后该对象就会被释放 h = null; // 把对象释放 // h.eat(); //当对象不存在时,调用该对象的属性和方法将报错(空指针) } } // 定义一个类(类型) class Horse{ // 在类中定义属性(特征) String name; int age; public void run(){ System.out.println("我是"+name+",我"+age+"岁,我还可以跑") } public void eat(){ System.out.println("我吃的很多") } }
声明一个类的变量在栈中,栈内存一般存储变量名,地址,基本数据类型。当new关键字实例化以后,便会在堆内存申请内存空间,栈内存的地址则会指向堆内存的区域。注意name也是名字,还是会指向另外的地址,这里抽象一下表达。
当一个对象没有被引用,堆内存会被GC垃圾回收;
总结:
new关键字:表示向内存申请空间,也表示实例化一个对象,创建一个对象。
一个对象在内存中的大小,由该对象的所有属性所占的内存大小的总和。引用类型变量在32为系统上占4个字节,在64位系统上占8个字节。加上而外的对象隐性数据所占的大小。
相同的类型才可以赋值。
不同的引用,指向同一个对象,任何引用改变对象的值,其他引用都会反映出来。
编程时要注意的问题,在确定不使用对象时,要尽早释放对象:引用=null;
当一个堆中的对象没有被任何引用变量所指向时,该对象会被JVM的GC程序认为是垃圾对象,从而被回收。
封装性是面向对象思想的三大特征之一。
封装性就是隐藏实现细节,仅对外提供访问接口。
封装有:
属性的封装、方法的封装、类的封装、组件的封装、模块化封装、系统级封装...
理解:如一台电脑的内部结构,由各种零配件组装而成,每个零配件又相互独立的提供功能
模块化、信息隐藏、代码重用、插件化易于调试、就有安全性
缺点:会影响执行效率;
/** * 封装性 * 如果属性没有封装,那么在本类之外创建对象后,可以直接访问属性 * private 关键字:访问权限修饰符 私有的,只能在本类中访问;public 公有修饰符 */ public class Test{ public static void main(String[] args){ Person p1 = new Person(); p1.name = "小小"; p1.age = 18; p1.setName("yiyi"); p1.setAge(18); System.out.println(p1.getName()); } } //封装之前 class Person{ String name; int age; } //封装之后: class Person{ // 属性是成员变量 private String name; private int age; // 参数及方法内定义的变量是局部变量 // 对外提供一个为name属性设值的方法 public void setName(String name){ this.name = name; } // 对外提供一个获取name属性的方法 public String getName(){ return name; } public void setAge(int age){ this.age= age; } public int getAge(){ return age; } }
成员变量:在类中定义
局部变量:在方法中定义或者方法的参数
成员变量:在堆内存(成员变量属于对象,对象进堆内存)
局部变量:在栈内存(局部变量属于方法,方法进栈内存)
成员变量:随着对象的创建而存在,随着对象的销毁而消失
局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
成员变量:由默认初始化值,引用类型默认为null
局部变量:没有默认初始化值,必须定义,赋值,然后才能使用
注意:局部变量名称可以和成员变量名称一样,在方法中使用的时候,采用的是就近原则。
构造方法就是类构造对象时调用的方法,用于对象的初始化工作
构造方法是实例化一个类的对象时,也就是new的时候,最先调用的方法。
构造方法是在类中定义的,构造方法的定义格式:方法名称与类名称相同,无返回值类型的声明。
对象的实例化语法:
Dog dog = new Dog(); //new Dog 后面有个括号,带括号表示调用了方法,此时调用的方法就是构造方法了。
public class Test{ public static void main(String[] args){ Dog dog = new Dog(); Dog dog1 = new Dog("wang",5); } } class Dog{ // 默认的构造方法 public Dog(){ System.out.println("构造方法") } public Dog(String name){ this.name = name; System.out.println("带一个参数构造方法") } // 构造方法的重载 public Dog(String name, int age){ // this(name); //调用其他构造方法时,此语句必须在第一句,在构造方法相互调用时必须要有出口 this.name = name; this.age = age; System.out.println("带参数构造方法") } }
构造方法名称与类名相同,没有返回值声明(包括void);
构造方法用于初始化数据(属性);
每一个类中都会有一个默认的无参的构造方法;
如果类中有显示的构造方法,那么默认构造方法将无效;
如果有显示的构造方法,还想保留默认构造方法,需要显示的写出来;
构造方法可以有多个,但参数不一样,称为构造方法的重载;
在构造方法中调用另一个构造方法,使用this(...),该句代码必须在第一句。
构造方法之间的调用,必须要有出口;
给对象初始化数据可以使用构造方法或setter方法,通常情况下,两者都会保留;
一个好的编程习惯是要保留默认的构造方法(为了方便一些框架代码使用反射来创建对象);
private Dog(){},构造方法私有化,当我们的需求是为了保证该类只有一个对象时。
什么时候一个类只需要一个对象?比如:工具类(没有属性,只有行为)并且该工具对象被频繁使用,权衡只用一个对象与产生多个对象的内存使用,来确定该类是否要定义为只需要一个对象。
在java中,this关键字是一个重要的概念,使用this可以完成下面的操作:
调用类中的属性
调用类中的方法或构造方法
表示当前对象
public class Test{ public static void main(String[] args){ Cat cat = new Cat(); cat.setName("小白");// cat调用了方法,所以cat就是当前对象 cat.setAge(2); cat.eat(); } } class Cat{ private String name; private int age; public void setName(String name){ //name=小白 this.name = name; // this代表当前对象 this表示cat,谁调用这个方法谁就是当前对象 } public void getName(){ return name; } public void setAge(int age){ this.age= age; } public void getAge(){ return age; } public void eat(){ // 在方法中使用this调用类中其他方法,this可以省略,this前可以使用当前类名.this System.out.println("我是"+Cat.this.getName()+",我爱吃鱼") System.out.println("我是"+this.name+",我爱吃鱼") } }
上述代码输出的结果为10。为什么呢?
输出结果为5,为什么呢?
这就是引用传递,变量存的是地址。
输出结果为小飞,为什么呢? 因为字符串本身就是一个对象。
输出结果为备备,
name在堆中存储的还是一个地址,指向另一块内存数据,下面这个p表示method方法中的p,然后调用name,重新赋值,这将改变name的地址,指向另一块内存数据,之前的"飞飞"变为垃圾对象。