Java面向对象
2020-09-15 本文已影响0人
曾梦想仗剑天涯
Java面向对象编程三个主要特征
- 封装:内部操作对外部不可见,内部操作都不可直接使用才是安全的
- 继承:在已有结构基础上,进行功能的扩充
- 多态:是在继承的基础上扩充而来的概念,指的是类型的转换处理
面向对象开发的三个步骤:
- OOA 面向对象的分析
- OOD 面向对象的设计
- OOP 面向对象的编程
类与对象
- 类是对某一类事物的共性的抽象概念,而对象描述的是一个具体的产物。
- 类是一个模板,而对象才是类可以使用的实例,先有类再有对象。
- 在类中一般都会由两个组成:
- 成员属性(Field):有些时候为了简化称为属性
- 操作方法(Method):定义对象具有的处理行为
类与对象的定义与使用
/**
定义类 class Person {}
声明并实例化对象 类名称 对象名称 = new 类名称()
Person per = new Person();
*/
class Person {
String name;
int age;
public void tell() {
System.out.println("name:" + name);
System.out.println("age:" + age);
}
}
public class JavaDemo {
public static void main(String [] arge) {
Person per = new Person();
per.name = "张三";
per.age = 18;
per.tell();
}
}
对象内存分析
- Java之中类属于引用数据类型,引用数据类型最大的困难之处在于要进行内存管理,同时在进行操作的时候也会发生内存关系的变化
- 堆内存:保存对象的具体信息,在程序当中堆内存空间的开辟是通过new来完成的
- 栈内存:保存的是一块堆内存的地址,通过地址找到堆内存,而后找到对象内容
-
程序报错 NullPointerException 代表引用数据类型使用错误
此图来源于李兴华老师
对象引用分析
- 类本身属于引用数据类型,既然是引用数据类型,那么就牵扯到内存的引用传递,所谓引用传递的本质:同一块堆内存空间可以被不同的栈内存所指向,也可以更换指向
/**
引用传递:Person per1 = new Person(); Person per2 = per1;
输出结果 age: 80
*/
public class JavaDemo {
public static void main(String [] arge) {
Person per1 = new Person();
per1.name = "张三";
per1.age = 18;
Person per2 = per1;
per2.age = 80;
per1.tell();
}
}
/**
通过方法引用传递
*/
public class JavaDemo {
public static void main(String [] arge) {
Person per1 = new Person();
per1.name = "张三";
per1.age = 18;
change()
per1.tell();
};
public static void change(Person temp) {
temp.age = 80;
}
}
引用传递与垃圾产生分析
- 引用传递如果处理不当,那么会造成垃圾的产生,即对堆内存处理不当将会产生垃圾
- 垃圾空间指的是:没有任何栈内存指向的堆内存空间,所有的垃圾将被GC(Grabage Collector 垃圾收集器)不定期进行回收并且释放无用内存空间,但是如果垃圾过多,就会影响到GC的处理性能,从而降低整体的程序性能,所以实际开发当中,垃圾产生的越少越好
/**
per1(栈内存地址)指向new Person()
per2(栈内存地址)指向new Person()
两个指向的new Person() 不同
per2 = per1 改变了per2指向
那么per2在定义时指向的堆内存将会变成垃圾
*/
public class JavaDemo {
public static void main(String [] arge) {
Person per1 = new Person();
Person per2 = new Person();
per1.name = "张三";
per1.age = 18;
per2.name = "李四";
per2.age = 80;
per2 = per1;
per2.age = 18;
per1.tell();
}
}
成员属性封装
- 在类之中的组成就是属性与方法,一般而言方法都是对外提供服务的,所以是不会进行封装处理,而对于属性由于其需要较高的安全性,所以往往需要对其进行保护,这个时候就需要采用封装性对属性进行保护
- 类中所有属性都必须使用private封装。并且属性要进行访问必须提供setter与getter方法。
/**
private关键字对属性进行封装
private String name;
private int age;
属性一旦封装之后对外部将不能够直接访问
可用setter getter获取/设置属性
*/
public void setName(String n) {
name = n;
};
public String getName() {
return name
};
per.setName("张三");
String perName = per.getName();
构造方法与匿名对象
- 构造方法是实现实例化对象中的属性初始化处理。
- 构造方法定义:
- 构造方法名称必须与类名称保持一致
- 构造方法不允许设置任何的返回值类型,即没有返回值定义
- 构造方法是在使用关键字new实例化对象的时候自动调用的
/**
public Person 即为构造方法
*/
class Person {
private String name;
private int age;
public Person(String n, int a){
name = n;
age = a;
}
public void tell(){
System.out.println("姓名:"+ name +"年龄:"+ age);
}
}
public class JavaDemo {
public static void main(String [] args) {
Person per =newPerson("张三", 18);
per.tell();
}
}
/**
Person定义对象的所属类型,类型决定了你可以调用的方法
per 实例化对象的名称
new 开辟一块新的堆内存空间
Person(“张三”, 18)调用有参构造,Person()调用无参构造函数,一个类至少存在一个构造方法
*/
Person per1 = new Person();
Person per2 = new Person(“张三”, 18);
- 程序编译器是根据代码结构进行编译处理,执行的时候是根据代码结构来处理
如果构造方法上使用了void,那么此结构就与普通方法的结构完全相同了,这样编译器会认为此方法是一个普通方法,普通方法与构造方法最大的区别:构造方法是在类对象实例化的时候调用的,而普通方法是在类对象实例化之后调用 - 构造方法本身就是一个方法,是方法就有重载性,构造方法的重载只需要考虑参数的类型和个数
this关键字
- 三类构造描述:
- 当前类中的属性: this.属性
- 当前类中的方法(构造方法,普通方法),thia(),this.方法名称()
- 构造方法必须在实例化新对象的时候调用,所以“this()” 的语句只允许放在构造方法的首行
- 构造方法互相调用时请保留有程序的出口,别形成死循环,造成递归调用
描述当前对象
- 使用this调用当前类中属性
- 只要是访问本类中属性的时候,要加上"this"实现访问
简单的Java类
- 指的是可以描述某一类信息的程序类。例如一本书、一个人。这个类之中没有特别复杂的逻辑操作,只作为一种信息存储的媒介存在。
- 简单Java类开发结构:
- 类名称一定要有意义,可以明确的描述某一类事物;
- 类之中的所有属性都必须使用private进行封装,同时封装后的属性必须要有setter和getter;
- 类之中可以提供无数的构造方法,但必须保留无参构造方法;
- 类之中不允许出现任何的输出语句,所有的内容获取必须返回;
class Dept {
private long deptNo;
private String deptName;
private String loc;
public Dept() {};
public Dept(long deptNo, String deptName, String loc) {
this.deptNo = deptNo;
this.deptName = deptName;
this.loc = loc;
};
public String getInfo() {
return "部门编号:" + this.deptNo + "、部门名称:" + this.deptName + "、部门位置:" + this.loc;
};
public void setDeptNo(long deptNo) {
this.deptNo = deptNo;
};
public long getDeptNo() {
return this.deptNo;
};
public void setDeptName(String deptName) {
this.deptName = deptName;
};
public String getDeptName() {
return this.deptName;
};
public void setLoc(String loc) {
this.loc = loc;
};
public String getLoc() {
return this.loc;
};
}
public class JavaStudy {
public static void main (String [] args) {
Dept dept = new Dept(18, "技术部", "石家庄");
System.out.println(dept.getInfo());
}
}
static定义属性
- static是一个关键字,主要是用来定义属性和方法,在一个类中,所有的属性一旦定义了实际内容,就会交由各自的堆内存空间进行保存。
- static是一个公共属性,虽然可以通过对象进行访问,但是应通过最高代表(类)来进行访问,所以static属性可以通过类名称来直接调用。
static属性虽然定义在类之中,但是不受到类实例化对象的控制,static属性可以在对象没有实例化的时候使用。
static定义方法
- static定义方法,同样可以直接通过类名称来调用。
- static方法只允许调用static属性或static方法;
- 非static方法允许调用static属性或static方法;
- static在回避实例化对象调用并且描述公共属性的情况下才会考虑使用static定义方法或者属性
static应用
/**
一个程序类,可以实现实例化对象个数的统计
每一次创建新的实例化对象都可以实现一个统计操作
实现属性自动命名处理
*/
class Book {
private String title;
private static int count = 0;
public Book () {
this("NOTTITLE - " + count++);
};
public Book (String title) {
this.title = title;
};
public void setTitle (String title) {
this.title = title;
};
public String getTitle () {
return this.title;
};
}
public class JavaStudy {
public static void main (String [] args) {
System.out.println(new Book("Java").getTitle());
System.out.println(new Book("JavaScript").getTitle());
System.out.println(new Book().getTitle());
System.out.println(new Book().getTitle());
}
}
代码块
- 在程序中使用“{}”定义的结构称为代码块,然后根据代码块出现的位置分为普通代码块、构造代码块、静态代码块、同步代码块。
/**
普通代码块:定义在一个方法中的代码块
在一个方法中可以对结构拆分,防止相同变量互相影响
*/
public class JavaStudy {
public static void main (String [] args) {
{
int x = 10;
System.out.println("x = " + x);
}
int x = 100;
System.out.println("x = " + x);
}
}
/**
构造代码块:定义在一个类之中
构造块会优先于构造方法执行,并且每一次实例化对象的时候都会调用构造块中的代码
*/
class Person {
public Person {
System.out.println("构造方法");
}
{
System.out.println("构造块");
}
}
/**
静态代码块:用static定义的代码块
分为主类中定义静态块,非主类定义静态块
执行顺序 静态代码块>构造代码块>构造方法
静态代码块只执行一次,主要是为类中静态属性初始化
*/
class Person {
static {
System.out.println("静态代码块");
}
}