面向对象
文章目录
面向对象与面向过程
- 两者都是一种看待问题、解决问题的思维方式、思想(不是一门语言)
- 两者的区别
- 面向过程:强调的是功能行为
- 面向对象:强调的是完成功能的对象
- 面向对象是基于面向过程的
类与对象
对象
具有特定的功能,能够解决待定问题的实体,就是一个对象
类
由若干个具有相同的特征和行为的对象的组成的集合,就是一个类
- 注:类是对象的集合,对象时类的个体
识别类的小技巧:一般名词都是类(名词提炼法)
类与对象的描述
类的设计
由若干个具有相同的特征和行为的对象的组成的集合,就是一个类,其中,特征用属性表示,行为用方法表示,所谓的属性也就是定义在类中的一个全局变量,在定义类时,使用关键字class
[访问权限修饰符] class 类名 {
//类体
//属性:描述所有对象的共有特征
//方法:描述所有对象共有的方法
}
//例子
public class Person{
String name;//姓名
int age;//年龄
public void eat() {}//吃
public void sleep() {}//睡
}
注意事项
- 类名:是一个标识符,遵循大驼峰命名法
- 一个java文件中可以写多个类,但只有一个与文件名相同的类,可以使用public
- 每一个类在编译后都会生成一个.class字节码文件,以类的名字命名
对象的实例化
实例化对象,其实就是从类中找到一个实体,使用关键字new来进行实例化
//实体类
class Person{
String name;//姓名
int age;//年龄
public void eat() {}//吃
public void sleep() {}//睡
}
//测试类
public class Test1{
public static void main(String[] args) {
Person person = new Person();
}
}
注:使用new实例化对象,是在堆上开辟空间。
匿名对象
-
定义:
匿名对象也就是没有名字的对象。
因为没有名字,所以当我们想使用匿名对象实现功能时,只能在创建对象的这个时刻使用一次.一旦使用完毕,这个对象我们就再也无法调用,变成了垃圾.系统会通过垃圾回收机制在某个时刻进行内存回收。
-
作用:
内存很宝贵,使用匿名对象可以更好的使用内存(随用随建,用完更快回收),节省内存。
-
使用的场景:
- 用匿名对象直接作为方法的参数;
- 用作匿名内部类。
//测试类 public class Test2{ public static void main(String[] args) { Person person = new Person(); person.age = 50; new Person();//无名字的对象---匿名对象 new Person().age = 10; //作为方法参数 chat(new Person); } public static void chat(Person person) { //一些功能 } } //实体类 class Person{ String name;//姓名 int age;//年龄 public void eat() {}//吃 public void sleep() {}//睡 }
-
多引用指向一个对象
//测试类 public class Test3{ public static void main(String[] args) { Person person = new Person(); Person person1 = person; //这里person和person1都指向堆中person那个对象,同一块地址 } } //实体类 class Person{ String name;//姓名 int age;//年龄 public void eat() {}//吃 public void sleep() {}//睡 }
类中的成员访问
成员分类
- 使用关键字static修饰的属性、方法, 被称为静态属性、静态方法;
- 没有使用关键字static修饰的属性、方法, 被称为非静态属性、非静态方法, 又被称为实例属性、实例方法。
static关键字
- 被static修饰的成员就变成了静态的.具有保值功能。
- 作用:
- 用于保值
- 用于工具类的创建
空间分配
- 静态的成员是属于类的,在类第一次被加载到内存中的时候,就已经分配空间了;(也就是方法区)
- 非静态的成员是属于对象的,在实例化对象的时候分配空间。(也就是堆区)
访问规则
- 静态成员需要使用类访问,非静态成员需要使用对象访问;
- 静态方法中可以直接访问本类中的静态成员,不能直接访问本类中的非静态成员;
- 非静态方法中可以直接访问本类中的静态成员,也可以直接访问本类中的非静态成员。
//测试类
public class Test4{
public static void main(String[] args) {
Person person = new Person();
//实例属性和方法访问依赖对象
person.name = "kaka";
person.age = 18;
person.eat();
person.sleep();
//静态属性和方法依赖类,但对象也能够访问到静态属性和方法
Person.COUNT = 2;
Person.show();
person.COUNT = 3;
person.show();
}
}
//实体类
class Person{
String name;//姓名
int age;//年龄
static int COUNT;
public void eat() {}//吃
public void sleep() {}//睡
public static void show() {}
}
关于静态与非静态、类与对象访问的问答:
-
为什么可以直接通过类名调用静态的成员?
当成员被static修饰之后就变成了静态的,会在class生成的同时放在静态方法区中一份,而静态方法区的特点是内容会随着程序的结束而释放,这里的成员已经不属于某一个实例对象,生命周期与字节码文件保持一致,大于某个实例对象,实例对象的创建与否不能影响他们的调用,可以直接使用类名调用,在用类名调用时,本质上是在使用字节码文件对象直接实现调用,这样即可以节省内存,又能提高效。
-
为什么不能使用类名调用非静态成员?
使用类名调用,本质上是在使用字节码文件对象直接实现调用,字节码文件对象的出现时间要早于某个实例对象,而非静态成员的生命周期是与实例对象保持一致,所以当有字节码文件对象时,不一定有实例对象,非静态成员,所以不能调用。
-
静态的成员方法和非静态的成员方法优先使用哪一个?
优先使用静态的成员方法;
原因:静态的方法比非静态的效率高,节省内存。
注意:但是有一种情况例外:当方法中必须使用非静态的成员变量时,必须使用非静态方法;
总结:被static修饰的成员变量会变成静态的成员变量,成员方法会变成静态的成员方法。
类是一种自定义的数据类型
- 类, 其实是一种自定义的引用数据类型, 这种类型可以作用于属性、方法参数、返回值…,之前怎么使用的基本数据类型, 就可以怎样使用这种类型。
- 注意:一个类型一旦创建出来,就是一个独立的数据类型,在他可见的范围内都是可以使用的,包括自己的内部。
this关键字
-
是一种引用数据类型,本身是一个关键字,用在类的实例方法或者构造方法中,代表的是当前的对象,保存的是当前对象的地址;当我们想在当前类的内部拿到当前对象的引用时,可以使用this。
-
this的功能总结:
- 用来区分成员变量和局部变量;
- 可以在构造方法内部调用其他重载的构造方法,提高代码的复用性,简化代码。
//实体类 class Person{ String name;//姓名 int age;//年龄 static int COUNT; public void setData(String name, int age) {//设置对象属性的一个方法 //区分了成员变量和局部变量 this.name = name; this.age = age; } public void eat() {}//吃 public void sleep() {}//睡 public static void show() {} }
-
this关键字的是否省略
- 当需要访问的属性与局部变量没有重名的时候, this关键字可以写, 也可以不写;
- 当需要访问的属性与局部变量重名的时候, this关键字必须写, 不可以省略。
//实体类 class Person{ String name;//姓名 int age;//年龄 static int COUNT; public void setData(String name, int nianling) {//设置对象属性的一个方法 //区分了成员变量和局部变量 this.name = name;//不可省略 age = nianling;//可省略 } public void eat() {}//吃 public void sleep() {}//睡 public static void show() {} }
构造方法(重)
-
概念:构造方法, 其实也是一个方法; 用于实例化对象, 在实例化对象的时候调用。
-
和普通的方法的区别:
- 构造方法的名字,必须和类名一致;
- 构造方法没有返回值,返回值类型部分不用写。
-
构造方法的意义:一般情况下,使用构造方法,是为了在实例化对象的同时,给一些属性进行初始化赋值;有参构造和无参构造说明了构造方法也是可以重载的。
//实体类 class Person{ String name;//姓名 int age;//年龄 static int COUNT; public Person() {//无参构造 this.name = ""; this.age = 18; } public Person(String name, int nianling) {//有参构造 this.name = name; this.age = age; } public void eat() {}//吃 public void sleep() {}//睡 public static void show() {} }
-
构造方法的使用:
//测试类 public class Test5{ public static void main(String[] args) { //通过无参构造实例化对象 Person person1 = new Person(); //通过有参构造实例化对象 Person person2 = new Person("xiaobai", 18); } }
-
构造方法的注意事项:
- 如果一个类中没有写构造方法, 系统会自动提供一个public权限的无参构造方法, 以便实例化对象;
- 如果一个类中写构造方法了, 此时系统将不再提供任何的默认的构造方法;
- 多个构造方法之间是重载的关系
-
this在构造方法中的使用
- 不能自己调用自己—死循环;
- 不能相互调用----死循环;
- this充当构造方法时,必须放在第一行;
- this在作为方法的时候,只能充当构造方法,不能作为其他方法;
- this的使用范围就是当前类的内部;
- 只有在非静态方法中,才可以使用this。
public class Test5 { public static void main(String[] args) { //利用系统默认的构造方法完成属性的初始化 //当我们自己创建了构造方法后,就不会再去调用系统默认的构造方法. Dog dog = new Dog(); dog.name = "拉布拉多"; Dog dog1 = new Dog("金毛"); System.out.println(dog1.name); } } class Dog { String name; int age; double height; //创建无参构造方法 //1.一旦创建了自己的构造方法,就不会再去调用系统默认的构造方法 public Dog() { //this();//自己调用自己----死循环 //系统自动对属性进行了初始化 System.out.println("这里是无参构造方法"); //this("土狗");//this充当构造方法时,必须放在第一行 } //创建有参构造方法 //功能:在对属性初始化后,并完成赋值 public Dog(String name) { //this("bing",20,2);//两个构造方法相互调用----死循环 this.name = name; } public Dog(String name, int age, double height) { //this充当的是构造方法 this(name); this.age = age; this.height = height; } public void run() { //这里name前面默认有个this name = "柯基"; System.out.println("跑步"); } }
代码段
构造代码段
直接在类中写的代码段, 就是构造代码段。
构造代码段中的代码, 在每次实例化对象的时候执行,执行顺序优先于构造方法.。 一般在构造方法中, 对对象的某些属性进行初始化的赋值。
构造代码段, 功能与无参构造方法是有重复的, 实际使用中, 以构造方法的使用较多。
public class Person {
{
System.out.println("这里就是构造代码段");
System.out.println("实例化对象的时候执行");
System.out.println("构造代码段的执行时机在构造方法之前");
}
{
System.out.println("一个类中可以写多个构造代码段");
System.out.println("多个构造代码段之间的执行顺序取决于书写的先后顺序");
}
}
静态代码段
直接在类中写的代码段, 用static修饰, 就是静态代码段。
静态代码段, 当类第一次加载到内存中的时候执行, 一般进行属性的初始化赋值, 或者进行资源加载,执行顺序优先于main 。
public class Person {
static {
System.out.println("这里就是静态代码段");
System.out.println("在类加载的时候执行");
}
static {
System.out.println("一个类中可以写多个静态代码段");
System.out.println("多个静态代码段之间的执行顺序取决于书写顺序");
}
}