面向对象编程-对象和类
1 面向对象编程概述
面向对象 的核心思想:复用,可以扩展。
面向对象三大基本特征:封装,继承,多态。
2 对象和类
创建类的目的是为了重复使用创造更多的对象。
2.1 软件中的对象
对象是指软件中个体或者逻辑上存在的个体,本质上对象就是软件中的一组一组有关系的数据,有相关的行为功能,找到软件中的对象就是识别出软件中的数据组。
2.2 类
类就是类型一致的对象(数据,方法)归纳出来的数据结构。类本身是根据对象归纳定义了对象的数据结构和功能方法,使用时候类作为对象的模板重复使用创建很多的对象。
案例:
class Ball{
int d;
double x;
double y;
int r;
int g;
int b;
Color color;
double offsetX;
double offsetY;
}
类的声明要点:
- 使用class关键字声明类
- 类名自拟,但是符合Java命名规范,类名首字母大写
- 类名后面是由{}声明的类体,类体中定义的成员,类的成员包括:属性,方法,构造器。代码块,内部类等。
- 类体中不能写语句,否则会有编译错误
- 根据对象归纳设计类,这个过程也称为根据对象抽象设计类
- 在同一个package中不能声明同名类!否则 编译错误。
2.3 创建对象
设计类的目的是作为模板复用创建对象。Java提供了new运算符用于类创建对象。创建对象的本质是在Java内存中创建一组相关数据,这组数据就是软件中的对象实例。利用类创建对象的好处是只有一个类就可以进行反复复用分配一组一组的数据了,减少了反复定义数据的戚烦!
案例:
public class Demo01{
public static void main(String[] args){
Ball ball1=new Ball();
Ball ball2=new Ball();
}
}
class Ball{
int d;
double x;
double y;
int r;
int g;
int b
Color color;
double offsetX;
double offsetY;
}
要点:
new运算用于利用类创建对象,每创建一个对象就会在内存中分配一组数据(对象);对象的数据称为对象的属性,由于是属于每个对象实例的变量,所以也称为“实例变量”多次调用new运算会创建多组数据(对象);
Java对象的属性(数据)有默认“O”值:
- 整数是0
- 浮点数是0.0
- 字符是编号为0的字符
- 布尔类型是false
- 引用类型是null
2.4 引用类型与引用类型变量
Java中除了基本类型以外的类型都是引用类型。比如: String, 数组,Ball等。 自己声明
的类也是引用类型,这样的好处是类型可以进行丰富的扩展。用引用类型声明的变量称为
引用类型变量,简称“引用”。使用基本类型变量的目的是可以控制基本类型数据,与此类似使
用引用类型变量的目的是可以控制对象数据。如:
Ball ball = new Ball();
ball.x = 5;
ball.y = 6;
ball变量就可以控制属于这个“泡泡”对象的数据类,其中ball.x=5,ball.y=6就是操作这一组
数据将泡泡移动到5,6位置上。其中“.” 是一个运算符,用于处理被ball引用对象的数据。
引用类型变量语法要点:
- 使用引用类型声明的变量是引用类型变量,也就是除了基本类型变量以外的变量都是引用
类型变量; - 引用类型变量也是变量,也要遵守变量命名的语法规则;
- 引用类型变量的值是对象的内存首地址,引用类型变量通过这个地址间接的引用了对象:
- 由于引用变量和对象直接是间接的关系,这也是“引用”一词的由来;
- 引用的值是对象的首地址,不是对象本身! 这个关系像气球和拴住气球的绳子之间的关系
- 引用变量可以赋值为null (空) ,表示变量没有引用任何对象;
- 在引用变量上使用“点'运算可以访问对象的属性/方法;
- 在null值的引用变量*问属性或者方法将出现“空指针异常”
完整案例:
public class Demo02{
public static void main(String[] args){
Ball ball1=new Ball();
Ball ball2=new Ball();
ball1.d=(int)(Math.random()*(60-10))+10;
ball1.x=Math.random()*(800-ball1.d);
ball1.y=Mathball1..random()*(600-ball1.d);
ball1.r=(int)(Math.random()*256);
ball1.g=(int)(Math.random()*256);
ball1.b=(int)(Math.random()*256);
ball1.color=new Color(ball1.r,ball1.g,ball1.b);
ball1.ball1.offsetx=Math.random()*(6-1)+1;
ball1.offsety=Math.random()*(6-1)+1;
ball1.offsetx=Math.random()>0.5 ? ball1.offsetX:-ball1.offsetX;
ball1.offsety=Math.random()>0.5 ? ball1.offsetY:-ball1.offsetY;
ball2.d=(int)(Math.random()*(60-10))+10;
ball2.x=Math.random()*(800-ball2.d);
ball2.y=Mathball1..random()*(600-ball2.d);
ball2.r=(int)(Math.random()*256);
ball2.g=(int)(Math.random()*256);
ball2.b=(int)(Math.random()*256);
ball2.color=new Color(ball2.r,ball2.g,ball2.b);
ball2.ball1.offsetx=Math.random()*(6-1)+1;
ball2.offsety=Math.random()*(6-1)+1;
ball2.offsetx=Math.random()>0.5 ? ball2.offsetX:-ball2.offsetX;
ball2.offsety=Math.random()>0.5 ? ball2.offsetY:-ball2.offsetY;
System.out.println(ball1.x);
System.out.println(ball2.x);
}
}
class Ball{
int d;
double x,y;
int r,g,b;
Color color;
double offsetX,offsetY;
}
3 构造器
3.1 使用构造器
构造器用于封装对象属性的初始化过程,利用构造器可以复用对象的初始化过程。利用构造器将对象属性初始化过程封装起来,下次再需要初始化对象属性时候,直接调用即可。
调用构造器创建对象:
Ball ball1=new Ball();
Ball ball2=new Ball();
构造器语法:
- 构造器也称为构造方法
- 构造器的名称与类名必须严格一致,包括大小写
- 构造器不能声明返回值,否则java作为方法处理
- 构造器封装对象属性初始化算法,这是构造器用途
- new运算调用构造器,创建对象,创建对象过程就是复用构造器初始化对象属性的过程。
完整案例:
public class Demo{
public static void main(String[] args){
Ball ball1=new Ball();
Ball ball2=new Ball();
System.out.println(ball1.x);
System.out.println(ball2.x);
}
}
class Ball{
int d;
double x,y;
int r,g,b;
Color color;
double offsetx,offsety;
public Ball() {
d=(int)(Math.random()*(60-10))+10;
x=Math.random()*(800-d);
y=Math.random()*(600-d);
r=(int)(Math.random()*256);
g=(int)(Math.random()*256);
b=(int)(Math.random()*256);
color=new Color(r,g,b);
offsetx=Math.random()*(6-1)+1;
offsety=Math.random()*(6-1)+1;
offsetx=Math.random()>0.5 ? offsetx:-offsetx;
offsety=Math.random()>0.5 ? offsety:-offsety;
}
}
3.2 有参数构造器
有参数构造器的好处就是可以复用参数赋值过程。
案例:
public class Demo02{
public static void main(String[] args){
Student tom=new Student("Tom",5);
System.out.println(tom.name);
System.out.println(tom.age);
}
}
class Student{
String name;
int age;
public Student(String name_,int age_){
name=name_;
age=age_;
}
}
3.3 this 引用
this是一个隐含局部变量,引用当前对象实例,访问当前对象的属性和方法。默认情况下可以省略不写,局部变量名称与当前对象的实例变量有冲突时候,则不能省略。
案例:
public class Demo{
public static void main(String[] args){
Student tom=new Student("Tom",5);
System.out.println(tom.name);
System.out.println(tom.age);
}
}
class Student{
String name;
int age;
public Student(String name,int age){
this.name=name;
this.age=age;
}
}
3.4 默认构造器
默认构造器是一个无参数,空方法体的构造器。
案例:
public class Demo03 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Foo foo=new Foo();//调用了默认构造器
//Goo goo=new Goo();//编译错误,Goo类中没有构造器Goo()
Goo goo=new Goo(5);//调用有参数的构造器
}
}
class Foo{
//Java会自动添加默认构造器
}
class Goo{
public Goo(int n) {
System.out.println("Goo(int)");
}
}
3.5 构造器重载
this()重用其他构造器,简化构造器的代码。this()必须在构造中使用,必须写在构造器的第一行!
案例:
public class Gzqcz {
/*
* 构造器重载
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Rectangle r1=new Rectangle();
Rectangle r2=new Rectangle(20);
Rectangle r3=new Rectangle(30,40);
System.out.println(r1.width);
System.out.println(r2.width);
System.out.println(r3.width);
System.out.println(r1.height);
System.out.println(r2.height);
System.out.println(r3.height);
}
}
class Rectangle{
int width;
int height;
public Rectangle() {
this(10,10);
}
public Rectangle(int width) {
//System.out.println(widht);
//调用其他构造语句 this()必须写在第一行
this(width,width);
}
public Rectangle(int width,int height) {
this.width=width;
this.height=height;
}
}
4 利用面向对象重构跑泡泡
4.1 声明Ball类
根据面向对象的设计思路,将Ball抽象为类。
Ball代码:
public class Ball {
int d;
double x;
double y;
int r;
int g;
int b;
Color color;
double offsetX;
double offsetY;
public Ball() {
d = (int)(Math.random()*(60-10))+10;//随机生成球的大小
x = Math.random()*(800-d);
y = Math.random()*(600-d);//球的范围
r = (int)(Math.random()*256);
g = (int)(Math.random()*256);
b = (int)(Math.random()*256);//随机颜色
color = new Color(r,g,b);
offsetx=Math.random()*5+1;
offsety=Math.random()*5+1;//随机速度
offsetx=Math.random()>0.5?offsetx:-offsetx;
offsety=Math.random()>0.5?offsety:-offsety;//随机运动方向
}
4.2 创建测试类Demo
创建图形界面应用程序类Demo,需要Ball数据时就创建一个Ball对象,一个Ball对象代表一组Ball数据。
public class Demo extends App{
Ball ball1=new Ball();
Ball ball2=new Ball();
public void painting(Graphics2D g) {
g.setColor(ball1.color);
//painting易错
ball1.x +=ball1.offsetX;
ball1.y +=ball1.offsetY;
if(ball1.x>800-ball1.d) {
ball1.offsetX=-ball1.offsetX;
System.out.println("碰到右边缘: "+ball1.x+","+ball1.d);
}else if(ball1.y>600-ball1.d) {
ball1.offsetY=-ball1.offsetY;
System.out.println("碰到下边缘: "+ball1.y+","+ball1.d);
}else if(ball1.x<0) {
ball1.offsetX=-ball1.offsetX;
System.out.println("碰到左边缘: "+ball1.x+","+ball1.d);
}else if(ball1.y<0) {
ball1.offsetY=-ball1.offsetY;
System.out.println("碰到上边缘: "+ball1.y+","+ball1.d);
}else {
System.out.println("正常飞行");
}
g.fillOval((int)ball1.x, (int)ball1.y, ball1.d, ball1.d);
g.setColor(ball2.color);
//painting易错
ball2.x +=ball2.offsetX;
ball2.y +=ball2.offsetY;
if(ball2.x>800-ball2.d) {
ball2.offsetX=-ball2.offsetX;
System.out.println("碰到右边缘: "+ball1.x+","+ball1.d);
}else if(ball2.y>600-ball2.d) {
ball2.offsetY=-ball2.offsetY;
System.out.println("碰到下边缘: "+ball1.y+","+ball1.d);
}else if(ball2.x<0) {
ball2.offsetX=-ball2.offsetX;
System.out.println("碰到左边缘: "+ball1.x+","+ball1.d);
}else if(ball2.y<0) {
ball2.offsetY=-ball2.offsetY;
System.out.println("碰到上边缘: "+ball1.y+","+ball1.d);
}else {
System.out.println("正常飞行");
System.out.println(ball1.x+","+ball1.y);
System.out.println(ball1.offsetx+","+ball1.offsety);
}
g.fillOval((int)ball2.x, (int)ball2.y, ball2.d, ball2.d);
}
public static void main(String[] args) {
Demo demo=new Demo();
demo.start();
}
}
5 方法
5.1 什么是方法
将冗余的计算过程封装成方法,在需要使用计算过程时候只需调用方法就可以复用这个计算过程。方法核心思想:复用计算过程。
5.2 声明方法
方法包含要素
- 修饰词:控制方法的可见范围
- 方法名:方法名称,需要遵守Java命名规范
- 参数列表:方法计算过程依赖的数据
- 方法体:方法中计算过程,往往可以复用的计算过程
- 返回值:方法的计算结果,声明返回值时候必须有return语句,如果没有返回值使用void声明返回值。
public class Cell{
double x;
double y;
}
public void eat(int x, int y){
//修饰词 返回值 方法名 参数
this.x+=x;
this.y+=y;//方法体
}
public int add(int a, int b){
return a+b;//返回计算结果
}
5.3 方法的参数,重载
参数语法:
- 方法参数列表可以包含多个参数
- 方法参数和方法内部声明的变量一样都是局部变量,方法结束后就销毁了
- 方法可以使用this,访问当前的实例变量,如与局部变量没有冲突,可以省略局部变量
public class Demo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Circle c1=new Circle(10,10,10);
System.out.println(c1.contains(5,5));//true
System.out.println(c1.contains(1,1));//false
Circle c2=new Circle(6,6,2);
System.out.println(c1.contains(c2));//true
Circle c3=new Circle(23,23,2);
System.out.println(c1.contains(c3));//false
}
}
class Circle{
int x;
int y;
int r;
public Circle(int x,int y,int r) {
this.x=x;
this.y=y;
this.r=r;
}
/*/
* 检测一个点 想,x,y是否在圆内部
*/
public boolean contains(int x,int y) {
int a=this.x-x;
int b=this.y-y;
double c=Math.sqrt(a*a+b*b);
return c<r;
}
//检查一个圆是否在另一个圆内部
public boolean contains(Circle c) {
int R=this.r;
int r=c.r;
if(R<r) {
return false;
}
int a=this.x-c.x;
int b=this.y-c.y;
double d=Math.sqrt(a*a+b*b);
return d<R-r;
}
}
6 重构跑泡泡抽取方法
将跑泡泡中的泡泡移动功能抽取到Ball类的方法中,在图形界面中直接调用即可,能大大简化代码:
完整Ball:
public class Ball {
int d;
double x;
double y;
int r;
int g;
int b;
Color color;
double offsetx;
double offsety;
public Ball() {
//初始化ball
d = (int)(Math.random()*(60-10))+10;//随机生成球的大小
x = Math.random()*(800-d);
y = Math.random()*(600-d);//球的范围
r = (int)(Math.random()*256);
g = (int)(Math.random()*256);
b = (int)(Math.random()*256);//随机颜色
color = new Color(r,g,b);
offsetx=Math.random()*5+1;
offsety=Math.random()*5+1;//随机速度
offsetx=Math.random()>0.5?offsetX:-offsetX;
offsety=Math.random()>0.5?offsetY:-offsetY;//随机运动方向
}
public void move() {
x+=offsetx;
y+=offsety;
if(x>800-d) {
offsetx=-offsetx;
//System.out.println("碰到右边缘: "+x+","+d);
}else if(y>600-d) {
offsety=-offsety;
//System.out.println("碰到下边缘: "+y+","+d);
}else if(x<0) {
offsetx=-offsetx;
//System.out.println("碰到左边缘: "+x+","+d);
}else if(y<0) {
offsety=-offsety;
//System.out.println("碰到上边缘: "+y+","+d);
}
//System.out.println(x+","+y);
//System.out.print(offsetx+","+offsety);
}
public void paint(Graphics2D g) {
g.setColor(color);
g.fillOval((int)x,(int)y,d,d);
}
}
图形页面简化了:
public class Demo extends App{
Ball ball1=new Ball();
Ball ball2=new Ball();
public void painting(Graphics2D g) {
ball1.move();
ball1.paint(g);
ball2.move();
ball2.paint(g);
}
public static void main(String[] args) {
Demo1 demo=new Demo();
demo.start();
}
}
7 Java对象内存管理
Java程序运算期间变量以及对象都是在内存中运算实现的。将Java如何在内存中管理对象,管理变量称为Java内存管理。Java内存是自动管理的,一般情况下不用人工干预。只有了解内存管理规则才能写出高质量的代码。
内存管理规则:
- Java 内存分为3个大区域:方法区、栈区、堆区
- 方法区是一个静态区,Java的类 (.class) 以及类中方法都加载到这个区域,在使用类之
前Java会将类自动加载到方法区,只加载一次。 - 栈是Java局部变量的空间,局部变量是指在方法中声明的变量,包括方法参数和this都是
局部变量。在方法运行期间所有局部变量都在栈中分配,当方法结束时候方法中分配的局
部变量全部销毁。 - 堆是Java对象空间,Java的全 部对象都在堆中分配,按照对象的属性在堆内存中分配对象
的存储空间。对象使用以后,当对象不再被引用时候,对象变成内存垃圾,Java垃圾回收
器会自动回收内存垃圾。