内容都是根据B站宋红康老师的视频总结以便复习的..
面向对象和面向过程都是编程思想,面向对象是相对于面向过程而言的,面向过程强调的是功能和行为,以函数为最小单位,考虑怎么做.面向对象,将功能封装进对象,强调具备了功能的对象(实例化),以类/对象为最小单位,考虑谁来做.
例子:把大象装进冰箱, 面向过程:打开冰箱 ; 抬起大象,装进冰箱; 关闭冰箱
面向对象: 面向对象则是对人类抽象,实现怎么样的行为,对冰箱进行抽象,有什么样的属性,对大象进行抽象,又会有什么样的行为. 设计类,类就是现实世界中名词的抽象,由谁来做,做的主体,这个问题解决了再来实现实例化.
两者的代码量差距不大,但是类可以更好的扩展, 只要设计好各种各样的类,然后再去设计子系统与子模块, 这样的面向对象的优势才能体现,一般在代码量比较大的项目中优势更大.
再举个例子,初创企业,员工很少,有活干活,都来干, 但是成熟企业,划分各个部门,有相应的规章制度,谁来干都是很清晰的.
面向对象中的两个基本要素:类和对象.class和Object是面向对象的核心概念,类是一类事物的描述,.是抽象的概念和定义,对象是实际存在的该类事物的每个个体,因而也被称为实例(instance).
面向对象程序设计就是类的设计,而类的设计就是类的成员的设计.
class Person{
//什么都没写,其实这也是个类
}
类的结构:属性和方法
Java代码世界是由各种各样的类构成的,(但是还有个概念是接口).
属性,(filed) 也叫成员变量,有些翻译为字段/域, 但其实就是属性,
方法,method,也叫成员方法.
类和对象的使用就是面向对象思想的实现
1创建类 .这是最复杂的一步,Java有没有生命力,就看有没有很多人去设计强大的类库,包括第三方开源的框架. class Person{//后面没有大括号,这里类前面也没有修饰符 String name; int age; boolean isMale; public void eat(){//目前方法前面统一用public修饰符 这是一个方法,返回值为void System.out.println("正在吃"); } public void sleep(int time){ //这个方法有参数 System.out.println("睡"+time+"分钟"); } } 下面两步是在main方法中编写的,而Person类则是创建在我们的测试类之外(如 public class Test{}) 2 创建类的对象 Person p1 =new Person();//new操作符new出对象 创建对象的格式是 类型 变量名 = new 类型(); 这样就创建了对象p1. 3 通过对象.属性 对象.方法() 调用对象的结构 p1.name = "Tim"; p1.age =20; //上面给属性赋值 p1.eat(); p1.sleep(5); // 调用方法
对象和对象创建的再理解,白马非马这个故事中,白马只是马类的一个实例化,颜色属性是白色,或者它是马类的一个继承,颜色属性是白色.创建类就是设计图纸,图纸造出来了就是根据图纸去创建一个个实体对象. 有一个对象,能调属性/方法,我们根据这个对象反推出类来,Java高级中要讲的反射.
体会多个对象之间的关系.
根据上面的代码,再创建一个p2对象 Person p2 =new Person(); p2.name 打印出来是null,而非报错,String的默认初始化值是null 注意打印p2是地址, p2我们已经new好了,它是栈空间对堆空间的引用, 指向了堆空间p2对象的地址. 同样的,打印p2.isMale是false 我们此时new了两次, 堆空间有两个对象,每个对象都有各自独立的属性(非static的) 这意味着修改p1 或者 p2 ,它们之间没有影响,不会影响两个对象在堆空间中各自的独立. Person p3 =p1; 跟上面创建对象不一样,我们创建了一个Person类型的变量,把p1赋值给它, 其实在在栈空间多了一个变量p3,它得到了p1的地址,和p1同时指向了堆空间中对应的对象. p3.name打印出来是Tom; p3.age =222; p1.age打印出来是222
对象的内存解析
JVM规定的内存结构图,这是完整的,.栈(虚拟机栈)存放局部变量,方法执行完,自动释放.堆,存放new出来的结构,对象和数组等 .方法区,存储已被加载的类信息,常量(字符串常量池),静态变量(也叫静态域,static关键字)以及即时编译器编译后的代码等数据.
堆(Heap),此内存区域的唯一目的
就是存放对象实例,几乎所有的对象
实例都在这里分配内存。这一点在
Java虚拟机规范中的描述是:所有的
对象实例以及数组都要在堆上分配。 通常所说的栈(Stack),是指虚拟机
栈。虚拟机栈用于存储局部变量等。
局部变量表存放了编译期可知长度的
各种基本数据类型(boolean、byte、
char 、 short 、 int 、 float 、 long 、
double)、对象引用(reference类型,
它不等同于对象本身,是对象在堆内
存的首地址)。 方法执行完,自动释
放。 方法区(Method Area),用于存储已
被虚拟机加载的类信息、常量、静态
变量、即时编译器编译后的代码等数
据
对象的内存解析:
Person p1 = new Person();
new 创建对象,在堆内有个首地址值,把这个地址值赋值给p1,
p1是在main方法中创建的变量,方法中创建的变量都是局部变量.
局部变量都存放在栈空间中,p1在栈空间中,值为p1对象的首地址值,
属性在堆空间中有默认初始化值,和数组一样,
name 字符串的默认初始化值是null
age int的默认初始化值是0
isMale的默认初始化值是false
p1.name = "Tom",
找到堆空间的中的p1对象,name属性赋值为"Tom",覆盖了原来的null.事实上,"Tom"不保存在堆空间中,在字符串常量池内,属于方法区
p1.isMale =true;
同样是 把isMale属性赋值为true
Person p2 = new Person(); 同样是创建了一个p2对象
仍然是在堆空间中有个p2对象的首地址值,赋值给栈空间中的p2变量
System.out.println(p2.name);打印出是null,因为是默认初始化值
Person p3 =p1;
栈空间中创建了一个局部变量p3,它的值是p1对象的地址
p3.age =10;
根据地址找到所指向的p1对象的age属性,把0修改为10
设计类就是设计类的成员,再回到类的成员属性和方法.
首先介绍局部变量和属性,属性和局部变量有什么注意的.他们的相同是定义变量的格式相同,(属性又叫成员变量), 数据类型 变量名 =变量值. 先声明,后使用. 变量都有对应的作用域.
不同点
1. 它们在类中的位置不同, 类中定义的变量就是属性,直接再类的一对括号内, 所以在main中方法写的变量是局部变量,它们不是在类的那个{}下面直接定义的. 而局部变量在类中只出现在方法内(类定义的方法),方法形参, 代码块内/构造器形参/构造器内的变量. class Car{ String name; String color; //上面是属性 public void run(double speed){ //形参,是局部变量 double speeds = speed *2; //方法中定义的变量. 局部变量 System.out.println("我能跑"+speed+",但是我最快能跑"+speeds); } } 2.关于权限修饰符的不同 属性:声明属性时,指明其权限,使用权限修饰符,常用的权限修饰符有 private,public,protected和缺省修饰符(前面什么都不写), 上面的属性就是用的缺省修饰符. private String name;Car创建的对象不能调用这个属性, ... 权限修饰符体现于结构被调用的时候可见性的大小(类的封装性) 局部变量:前面不能使用权限修饰符,可以理解为方法的权限(public)就是局部变量的权限 3.关于默认初始化值. 属性的默认初始化值同数组, byte short int -->0 long -->0L flaoat :0.0f double 0.0; boolean false; char : '\0'=0='\u0000'; 引用数据类型(类,数组,接口):null 而局部变量没有默认初始化值, 在main中声明一个变量int num; 打印num会报错 类中定义一个方法 public void write(Sring str){//如果调用方法不给实参的话就会报错,说明它没有null这个默认初始化值 int a ;//局部变量在这里不给赋值也会报错 } 4.局部变量和属性在内存中的位置不同 属性在堆空间中 局部变量在栈空间中
接下来讲方法,方法举例和声明的格式
属性是变量,而方法是类中定义的功能.
Scanner 类的next 方法,Arrays类的toString方法,sort方法.equals方法
方法的声明: 权限修饰符 返回值类型 方法名(形参列表 args1,args2,...){ //方法体 } 目前用到的方法的权限修饰符都是public, 当然还有没用到的static final abstract 等特殊关键字来修饰方法. class Customer{ String name; int age; public void eat(){//无形参 System.out.println("客户正在吃饭"); } public void sleep(int hour){ //有形参,调用时传入 System.out.println("睡个"+hour+"小时"); } public String getName(){ //返回值类型是String ,有这个属性,不要形参 return name;//返回name } public String getNation(String nation){ String info = "我的祖国是"+nation; //定义了一个字符串局部变量,返回这个局部变量 return info; } }
方法的注意点: 1.有权限修饰符,同属性,public private protected 和缺省(不写修饰符) 关于权限修饰符在谈封装性细说 类中定义了一个private void noSee(){},外部不能调用这个方法. 2.返回值类型 这个看实际需求,有返回值,必须给定返回值类型并且return相应的返回值 没有返回值则用void表示返回值为空 return "Tom";返回一个常量也可以,但是必须要有return关键字. 有个注意点方法要求返回一个字符串 里面有判断逻辑 if (age>19){ return name; }//这样是错误的,age小于19就不返回,但是声明的是需要返回值的 所以加上一个else{ return "Tom"; } 关于返回值类型为void 我们没有写return关键字,实际上是省略了 return ;
reurn关键字的使用,使用在方法体中,作用时结束方法或者对于有返回值的方法给出返回值.
方法使用的注意点 1. 方法中可以调用类中的属性和方法 类A中调用 属性x 类A中的 meth1 调用meth2 ,meth1调用meth1,会导致栈溢出 那么方法名meth1应该也是存放在栈空间中的 2. 方法中不能定义方法 public void outter(){ public void inner(){ ; } } 这是错误的
面向对象的课后练习
我自己写的使用就脑抽了 public class HomeWork{ public static void main(String[] args){ ... } } 这里我写的public class A{ } 现在类都写在public类下面 写class A{ } 我这样是把定义的类和测试类都写在一个文件下面了. 实际开发中,一个文件就写一个类,并且各个类还不能重名. 我定义的类创建一个文件 public class A{//这里可以用public了 } 在主测试类的文件下 public class Atest{ //main方法是程序的入口,入口内测试. }
创建Person类的对象,设置该对象的name、 age和sex属性,调用study方法,输出字符串 “studying”,调用showAge()方法显示age值,调用 addAge()方法给对象的age属性值增加2岁。 class Person{ int age; ... public addAge(int i){ age+=i; } ... } 代码没有写全,这里讲一下这个addAge方法,首先我们实例化了对象 p1 不管我们给没有给p1 这个对象的age属性赋值,addAge方法都是可用的 1. 不赋值age, age在堆内是int默认值 0 p1.addAge(2),调用这个方法.我们创建了一个局部变量i在内存中,值是2,把age的值0+2后赋值给age; 方法调用结束,局部变量i被当做垃圾回收. 2.赋值了age p1.age =18;堆空间中的属性age变为18 , 调用方法,创建局部变量i,值为2,加值赋值给age,方法调用结束,i被当做垃圾回收.
课后练习 .圆的面积 有半径属性,方法可以直接调用属性,方法不传参数.
课后练习,对象数组. 实例化二十个学生对象 因而不能用new去创建20个. 用数组,数组有20个元素,每个元素是对象. 创建Person数组 Person[] persons = new Person[20]; new了一个数组,堆空间中有一个数组,数组有20个元素,因为元素是对象, 对象是引用数据类型,因而是默认值null person[x]打印出来是null; persons在栈空间,变量是Person[]数组在堆空间的首地址, 怎么实例化对象呢? 数组的元素是对象,并且Person类创建的对象.只是还没创建, 相当于 每个元素都是 Person p; 把每个实例对象new出来就行了 for (int i =0;i<persons.lenth;i++) { persons[i] = new Person(); //每个元素从原来的null,变成得到一个Person对象的首地址 //创建了20个对象, } 类定义 class Person{ ... }