一天可以new无数个对象,可是老妈还在让我找对象。。。
面向对象的三个基本特点:1. 封装性 2. 继承 3. 多态
易于扩展和维护,封装性好,复用性高
一、面向过程 VS 面向对象
(就喜欢紫色)
面向过程完成事情的步骤,我们一个一个方法实现步骤,然后依次调用,而面向对象是使用某些对象
面向对象优点:
- 我们不需要知道某些方法是如何构建的,封装性好
- 易于管理
面向对象缺点:执行效率
例1:做菜
- 过程
1. 洗菜 2. 放油热锅 3. 炒菜
用户是个厨师,知道所有的步骤
- 对象
厨师对象,有做菜的动态属性
用户是个食客,通知厨师做菜即可
例2:某个游戏的过程(奇葩的游戏,每次玩家执行动作之前都跳一下~不要问我是什么游戏)
玩家1输入
jump()
action(参数)
玩家2输入
jump()
action(参数)
...n个玩家...
判断返回第一步
此时,我们想要给某个jump()方法添加一个参数(这里不关心参数哪里来的)
- 过程
想给jump()加入一个参数height,此时程序里面所有用到该jump()方法的地方都要修改
- 对象
后台对象b
玩家1输入
b.implement(参数)
玩家2输入
b.implement(参数)
...n个玩家...
判断返回第一步
1. 技能类Skill,我们需要修改相关的动态属性jump()设定跳高度限制->jump(参数1)
2. 对于后台类
Skill s = new Skill
implement(参数){
获得输入
s.jump()-》s.jump(参数1)
s.action(参数)
}
例3:一个人可以养一只宠物,主人一逗它,它就叫
- 过程
主人逗它,判断宠物类型,宠物叫,但是不同的主人可能养了不同的宠物,猫是喵喵叫,狗是汪汪叫,小鸟是唧唧喳喳叫......我们很难一下子把所有的宠物可能都列出来(对于面向过程,我们需要添加方法,然后修改逻辑判断)
- 对象
动物对象
人对象
人调用动物的叫方法,如果是猫,我们可以创建猫子类,并重写自己的叫方法,不需要修改其他地方的代码
二、对象
对象利用计算机语言对问题域中事务进行描述,类用来描述对象的一个抽象的概念,类可以看作是对象的模板,对象可以看成该类的一个具体实例
- 属性(静态属性)
- 方法(动态属性)
三、类之间的关系
- 关联
这是最弱的一种关系(一个类中的方法参数是另一个类),比如”使用“,人使用车
- 继承
子类拥有父类的属性,什么是什么的一种,JAVA只允许单继承(每一个类只能有一个父类,但一个父类可以有多个子类),多继承可以依靠接口实现
- 聚合
组合 VS 聚集
聚合表示了整体和部分的关系,而根据这种关系的松紧耦合又分为了聚集和组合,组合的每一个部分都是必不可少的,就像人不能没有大脑,而鸟群可以少了一只鸟
- 实现
实现接口,不同的对象对某个方法有不同的实现方式
- 多态
对象都有对外服务的接口,通过继承可以复用,对象隐藏内部服务的实现通过聚合可以复用。组件时比对象更高层次上的复用,相当于好多对象,过程的组合
四、类的定义
【修饰符】class 类名{
成员变量
方法
}
修饰符: public, protected, private, 缺省
成员变量(注意它与局部变量有初始化的区别),它的作用域是整个类,注意类中非static成员变量或者方法不能用在static的方法中,因为static的类成员或者方法是针对所有该类所有对象的,而非static的类成员或方法是针对某个对象的。只有实例化类时,非静态的成员才被初始化,但是我们可以直接调用静态方法,此时如果方法内有非静态成员变量就会出错~
http://blog.sina.com.cn/s/blog_411fed0c0102vh5x.html
静态方法的内存空间是在加载到内存后就被分配到的,而不是等到调用的时候才给分配。静态方法被加载到了内存,分配了空间,无论你是否使用,它就在那里,有且只有一个就它自己。无论多少个线程调用,都是调用的它自己就那么一个。 不同通过类的对象进行调用的方法,那种方法初始化类的对象的时候才被分配空间。而且java有垃圾回收机制,跑出作用域之后它所占的内存就会被回收。
调用非static方法
static void m(Object obj) {
obj.nonStaticM();
}
五、引用
引用类型一般占用两字节(虚拟的物理地址)
code seg: 类,方法
data seg: 静态数据和方法,字符串
stack: 执行过程中的临时变量
heap: 实例,不同的实例可能是不同的大小,因为成员变量值可能是不同的,所以不能实现分配大小
六、构造方法
- 初始化对象的函数,new创建实例的时候调用
- 名字和类同名
- 没有返回值
- 如果没有构造方法,编译器自动添加:
类名(){}
- 但是一旦一个类定义了一个构造方法,系统就不会自动添加
七、命名规则
- 类名首字母要大写,文件名与public类名相同
- 变量名和方法名要小写
- 运用驼峰标识,如furColor
八、内存解析
注意一个内存块数据,没有任何引用指向它的时候的时候就会被自动回收
class BirthDate {
private int day;
private int month;
private int year;
public BirthDate(int d, int m, int y) {
day = d;
month = m;
year = y;
}
public void setDay(int d) {
day = d;
}
public void setMonth(int m) {
month = m;
}
public void setYear(int y) {
year = y;
}
public int getDay() {
return day;
}
public int getMonth() {
return month;
}
public int getYear() {
return year;
}
public void display() {
System.out.println
(day + " - " + month + " - " + year);
}
}
public class Test{
public static void main(String args[]){
Test test = new Test();
int date = 9;
BirthDate d1= new BirthDate(7,7,1970);
BirthDate d2= new BirthDate(1,1,2000);
test.change1(date);
test.change2(d1);
test.change3(d2);
System.out.println("date=" + date);
d1.display();
d2.display();
}
public void change1(int i){
i = 1234;
}
public void change2(BirthDate b) {
b = new BirthDate(22,2,2004);
}
public void change3(BirthDate b) {
b.setDay(22);
}
}
一个内存块,除了this对自身的引用外,再无其他的引用指向它时~图中x表示临时的~
class Point {
private double x;
private double y;
Point(double x1, double y1) {
x = x1;
y = y1;
}
public double getX() { return x; }
public double getY() { return y; }
public void setX(double i) { x = i; }
public void setY(double i) { y = i; }
}
class Circle {
private Point o;
private double radius;
Circle(Point p, double r) {
o = p;
radius = r;
}
Circle(double r) {
o = new Point(0.0, 0.0);
radius = r;
}
boolean contains(Point p) {
double x = p.getX() - o.getX();
double y = p.getY() - o.getY();
if(x*x + y*y > radius * radius) return false;
else return true;
}
public void setO(double x, double y) {
o.setX(x);
o.setY(y);
}
public Point getO() { return o; }
public double getRadius() { return radius;}
public void setRadius(double r) { radius = r;}
public double area() {
return 3.14 * radius * radius;
}
}
public class TestCircle {
public static void main(String args[]) {
Circle c1 = new Circle(new Point(1.0,2.0), 2.0);
Circle c2 = new Circle(5.0);
System.out.println("c1:("+c1.getO().getX()+","
+c1.getO().getY()+"),"+c1.getRadius());
System.out.println("c2:("+c2.getO().getX()
+","+c2.getO().getY()+"),"+c2.getRadius());
System.out.println("c1 area = "+c1.area());
System.out.println("c1 area = "+c2.area());
c1.setO(5,6);
c2.setRadius(9.0);
System.out.println("c1:("+c1.getO().getX()+","
+c1.getO().getY()+"),"+c1.getRadius());
System.out.println("c2:("+c2.getO().getX()+","
+c2.getO().getY()+"),"+c2.getRadius());
System.out.println("c1 area = "+c1.area());
System.out.println("c1 area = "+c2.area());
Point p1 = new Point(5.2, 6.3);
System.out.println(c1.contains(p1));
System.out.println(c1.contains(new Point(10.0,9.0)));
}
}
九、方法重载overload
我们可以在一个类中定义相同名字的方法(但是参数是不同的,比如数据类型,参数个数),调用时,会根据不同的参数表选择对应的方法,构造方法也可以被重载
十、关键字this
this指向使用当前方法的对象,this可以被看做一个变量,是当前对象的引用,每个对象中都存在一个this
public class Leaf {
int i = 1;
Leaf(int i) {
this.i = i;
}
Leaf increament() {
i++;
return this;
}
void print() {
System.out.println("i="+i);
}
public static void main(String args[]){
Leaf leaf = new Leaf(100);
leaf.increament().increament().print();
}
}
结果是:
i=102
十一、关键字static
static类型的数据,不需要创建实例就已经在内存里面了
static方法和数据都在数据区内
- 静态成员变量(存放在数据区),为该类的公共变量,在第一次使用时被初始化,对于该类的所有对象来说,static成员变量只有一份
- 静态方法,不针对某个对象调用,所以在static方法中不可访问非static成员,可以通过对象引用或者类名访问静态成员
http://blog.youkuaiyun.com/peterwin1987/article/details/7571808
static方法就是类装载的时候就加载进来了,而非static方法是调用的时候才装载到内存
http://zhidao.baidu.com/question/1817880738458676908.html
public class Cat {
private static int sid = 0;
private String name;
int id;
Cat(String name) {
this.name = name;
id = sid++;
}
public void info(){
System.out.println
("My name is "+name+" No."+id);
}
public static void main(String arg[]){
Cat.sid = 100;
Cat mimi = new Cat("mimi");
mimi.sid = 2000;
Cat pipi = new Cat("pipi");
mimi.info();
pipi.info();
}
}
十二、package和import
package: 提供类的多重命名空间,不同的包可以含有相同名字的类,包路径规则通常是把公司域名倒过来比如net.princeton.包名,此时我们需要将net的上一层目录放入classpath中。如果程序没有package语句,则默认指定为无名包
- 编译出来的class文件必须位于正确的目录下面,并在classpath中添加该目录
- 如果想要在另一个类用这个包里的类,必须把名字写全,或者import(".",包)
- 不要把源代码放到放class的包中,可能会出错
Eclipse为不同的项目设置不同的classpath,不共享class文件
一些主要的包:
目录jdk/jre/lib/rt.jar/java
java.lang 包含一些JAVA的核心类,如String, Math, Integer, System, Thread等,默认引入
java.awt 与界面GUI相关的类
java.applet applet运行所需的一些类
java.net 网络相关的操作的类
java.io 提供多种输入、输出功能的类
java.util 一些实用的工具类,如定义系统特性,使用与日期日历相关的函数
classpath里面的jar包目录包含了jar包的名字
jar -cvf xx.jar *.* 解压压缩包
十三、继承和权限
关键字extends
子类拥有基类所有的成员变量和方法,只支持单继承,一个子类只能有一个基类,但一个基类可以有多个子类
修饰符有4个权限:public, private, protected, 缺省
class只能缺省或被public修饰
对于default和protected来说,其实应该这样讲,不同包中的类不能继承default类,而且不同包中的子类不能访问父类的default成员
十四、重写override
对父类方法进行重写(必须有相同的名称,参数和返回类型),重写方法不能使用比被重写的方法采用更严格的权限,里氏替换原则,子类对象可以被当成父类对象使用
十五、关键字super
使用super来引用父类的this
对于子类的构造方法,必须使用父类的构造方法,换言之,我们创建子类的同时创建了父类,我们可以使用super来实现,this可以用来调用本类的另外构造方法。如果子类没有调用基类的构造方法,系统默认调用基类的无参数构造方法,但是如果父类没有无参构造函数,则出错。super都写在第一行。
多看例子就懂了吧~
class Parent {
public int value;
public void f() {
value = 100;
System.out.println("Parent: "+value);
}
}
class Child extends Parent {
public int value;
public void f() {
super.f();
value = 200;
System.out.println("Child: "+value);
System.out.println("parent: "+super.value);
}
}
public class TestSuper {
public static void main(String args[]) {
Child c = new Child();
c.f();
}
}
结果:
Parent: 100
Child: 200
parent: 100
class A {
A() {
print("A()");
}
protected void print(String a) {
System.out.println(a);
}
public void f() {
print("A:f()");
}
}
class B extends A {
B() {
print("B()");
}
public void f() {
print("B:f()");
}
}
public class TestSuper2 {
public static void main(String[] args) {
B b = new B();
b.f();
}
}
结果:
A()
B()
B:f()
class Person1 {
private String name;
private String location;
Person1(String name) {
this.name = name;
location = "Beijing" ;
}
Person1(String name, String location) {
this.name = name;
this.location = location;
}
public String info() {
return "name: "+name+" location: "+location;
}
}
class Student1 extends Person1 {
private String school;
Student1(String name, String school) {
this(name, "beijing", school);
}
Student1(String name, String location, String school) {
super(name, location);
this.school = school;
}
public String info() {
return super.info()+" school: "+school;
}
}
public class TestSuper3 {
public static void main(String[] args) {
Student1 sd =new Student1("Mike", "IC");
System.out.println(sd.info());
}
}
结果:
name: Mike location: beijing school: IC
十六、大基类Object
Object是所有类的基类,当我们没写extends的时候,就默认继承Object
属性Class, 方法clone,getClass,toString,hashcode,equals,finalize等
十七、hashcode
java hash好白痴的,因为可能会发生两个不同内容对应同一个key的可能
十八、toString
Object类定义了一个public String toString()方法,返回String类型,描述当前对象有关信息,当String与其他类型进行数据连接时会自动调用这个函数,如System.out.println("info"+person),可以根据需要在子类中重写
toString(对象)的结果是类名@hash值
十九、equals方法
Object类还提供了public boolean equals(Object obj)方法,判断两个对象是否相等,默认是根据引用对象是否指向同一个来判断(与==作用相同),但是我们可以重写来根据对象的内容,而不根据引用来判断:
if(obj==null) return false;
else{
if(obj instanceof Cat){
Cat c=(Cat)obj;
if(c.color==this.color……){
return true;
}
}
}
return false;
public class TestEqual {
public static void main(String[] args) {
Integer i1 = new Integer(1);
Integer i2 = new Integer(1);
System.out.println(i1 == i2);
System.out.println(i1.equals(i2));
Mao m1 = new Mao("A", "A");
Mao m2 = new Mao("A", "A");
System.out.println(m1 == m2);
System.out.println(m1.equals(m2));
}
}
class Mao {
String name;
String color;
Mao(String n,String c){
name = n; color = c;
}
结果:
false
true
false
true
二十、对象转型castingclass Animal1 {
public String name;
Animal1(String name) {
this.name = name;
}
}
class Cat1 extends Animal1{
public String color;
Cat1(String name, String color) {
super(name);
this.color = color;
}
void f(){
System.out.println("喵喵喵~");
}
}
public class TestCasting {
public static void main(String args[]) {
String name = "Shirley", color = "Brown";
String name1 = "Bobby", color1 = "Black";
Cat1 c1 = new Cat1(name,color);
Animal1 c2 = new Cat1(name1,color1); //upcasting
System.out.println("cat1, name: "+c1.name+" color: "+c1.color);
c1.f();
//System.out.print("cat2, name: "+c2.name+" color: "+c2.color);不能执行,因为父类不能调用子类的成员变量color
//c2.f();不能执行,因为是Animal1引用类型变量,不能调用子类的成员
//downcasting
if (c2 instanceof Cat1) {
Cat1 c2_2 = (Cat1) c2;
System.out.println("cat2, name: "+c2_2.name+" color: "+c2_2.color);
c2_2.f();
}
}
}
二十二、动态绑定
动态绑定(多态,池绑定)
执行期间绑定,根据实际类调用相应的方法,而不是编译期间绑定,实现条件:
- 继承
- 重写
- 父类引用指向子类对象
class Animal2 {
public void enjoy() {
System.out.println("叫");
}
}
class Person2 {
String name;
Animal2 a2;
Person2(Animal2 a2, String name) {
this.a2 = a2;
this.name = name;
}
void petEnjoy(){
a2.enjoy();
}
}
class Bird extends Animal2 {
public void enjoy() {
System.out.println("唧唧喳喳");
}
}
class Dog1 extends Animal2 {
public void enjoy() {
System.out.println("汪汪汪");
}
}
public class TestPool {
public static void main(String args[]) {
Animal2 b = new Bird();
Animal2 d = new Dog1();
Person2 p1 = new Person2(b, "Amy");
Person2 p2 = new Person2(d, "Jack");
System.out.print(p1.name+"'s pet ");
p1.petEnjoy();
System.out.print(p2.name+"'s pet ");
p2.petEnjoy();
}
}
结果:
Amy's pet 唧唧喳喳
Jack's pet 汪汪汪
前面学过,父类不能调用子类的方法,但是看下多态,当子类中有相同名字和参数的方法时,就调用子类的
二十三、抽象类
关键字abstract
看下动态绑定的例子,有没有发现其实那个Animal的enjoy方法根本不需要实现,此时抽象方法就被引入了,抽象方法的拥有类必须为抽象类(但是抽象类除了抽象方法还可以拥有普通的成员变量和普通的方法),抽象方法只需要被声明而不实现,所以抽象类必须被继承,方法必须被重写,抽象类不能实例化,抽象可以继承抽象,注意抽象类依然保持单继承性。
二十四、关键字final
final变量的值不能被改变,方法不能被重写,类不能被继承,这样可以保护数据。方法参数如果是final类型的话,这个参数在方法中不能被改变,如果参数是个引用,则该引用不能指向别的对象,但是其实对象内的值还是可以被修改的~
public class TestFinal {
void execute(int s){
s = s+3;
System.out.println(s);
}
public static void main(String args[]) {
final int ii = 3;
testFinal tf = new testFinal();
tf.execute(ii);
}
}结果是:6
因为我们只是把ii的值3传给对象s,而不是s就是ii对象,此时将execute参数变成final int s,此时s就不能改变
String, Math和一些基础类型包装类都是final类型的
二十五、接口
关键字interface, implements
接口是对实物的属性和行为更高层次的抽象,是抽象方法和常量值的定义的集合,从本质上看,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现。多个无关的类可以实现同一个接口,而且一个类可以实现多个接口,实现多态性,接口可以继承其他的接口,添加新的属性和抽象方法,采取对修改关闭,对扩展开放得开闭原则
接口中的属性默认都是public static final的,为什么??
- 首先我们定义接口属性,希望别人能用上,是所有类都可以拥有的属性,如果具体实现类不能使用该属性,不就没有意义了嘛(同理,接口和接口方法也都是默认public)
- static的话,所有类共有的特性,如果非static的话,只有类创建实例的时候才能拥有这些方法,那么就不能被继承啦,并且一个类可以继承多个接口,如果出现重名不好区分(
public Interface Interface1 {
void getDesc();
}
public Interface Interface2 {
void getDesc();
}
public class TestInterface implements Interface1, Interface2 {void getDesc(); //因为getDesc是静态的,不会出错
}
但是如果A接口底下有一个double getMoney()方法,而B接口下有一个void getMoney()的方法,此时一个类同时实现这两个接口,就不好办了)
http://bbs.itheima.com/thread-162971-1-1.html
- 接口的成员不能修改,如果不是final的话,子类就可以修改,不符合开闭原则 ,就想我们有一个模板,希望后面可以添加功能,并不修改本来的功能
interface Singer {
void sing();
}
interface Painter {
void paint();
}
class Student3 implements Singer {
public void sing() {
System.out.println("sing3");
}
}
class Student4 implements Singer, Painter {
public void paint() {
System.out.println("paint4");
}
public void sing() {
System.out.println("sing4");
}
}
public class TestInterface {
public static void main(String args[]) {
Singer s1 = new Student3();
s1.sing();
Singer s2 = new Student4();
s2.sing();
//s4.paint(); 执行错误
Painter p = (Painter)s2;
//p.sing(); 执行错误
p.paint();
}
}
记下一些MAC快捷键:
cmd+m
cmd+n
cmd+f
shift+cmd+g
cmd+tab
Reference:
1. 马士兵JAVA基础视频

被折叠的 条评论
为什么被折叠?



