1. 面向对象的理解:
特点:1. 面向对象就是更符合人们思考习惯的一种思想。
2. 从面向过程的执行者,转变成了面向对象的指挥者
3. 面向对象将复杂的事情简单化了。
4. 在实现功能,先找java当中是不是提供好了相关的对象,没有对象自己造一个对象。比如说公司招聘人员找不到人的 时,这时公司就需要自己在公司内部培养人,也就是自己造对象。
其实面向对象是一种思想,是面向过程而言,将复杂的事情变的更简单了。
通过把大象放到冰箱里这个列子来理解面向对象的概念:
面向过程:把冰箱门打开、存储大象、关闭冰箱;强调的过程注重行为;
面向对象:冰箱.打开、冰箱.存储、冰箱.关闭;强调的是冰箱这个对象。
★面试题:你怎么理解面向对象?
首先说面向对象的特点:它是一种思想,它让复杂的问题简单化,它把执行者变成了指挥者。
然后举例子来说明,最猛的就是结合实际场景来说:其实面试官你就是在用面向对象的思想在思考问题,为什么这么 说?因为公司业务蒸蒸日上,需要招更多的人来完成项目,所以才在这里招聘人员,你需要找一些具备专业编程经验的人,来 帮公司完成工作,那么我就是那个对象,因为我具备专业编程能力,你就是那个指挥者,指挥我来做事,至于我怎么去完成编 程任务,你是不需要去知道,你只要结果了就可以了,这其实就是把你之前的工作简化了,你不必再事必躬亲了。这就是面向 对象思想的体现。
同时可以结合去饭店吃饭,在家做事等等列子来说明面向对象的思想。
2. 类和对象关系:
1. 类到底是什么?
类就是对现实生活中事物的描述,描述中包含了该类事物的共性内容。class Car { String color; int num; void run() { } }
在类中定义的变量和函数都称为类中的成员。
成员:成员变量---属性;
成员函数---行为:
如上面代码中,num和color是成员属性;而run()是成员函数。
2. 什么是对象?
对象就是该类事物实实在在存在的个体。
Eg:现实生活中的对象:张三、李四
想要描述:提取对象中的共性内容,对具体的抽象。
描述时:这些对象的共性有姓名、年龄、性别、学习java的功能。
对象也可以理解为其实就是个容器,用来存储更多的数据,存储的都是每一个对象特有的数据,而类就是这些数据所属 的属性。
如:用java语言来描述一个小汽车;描述事物:无非就是描述事物的属性和行为;属性:轮胎数、颜色;行为:运行
class Car{ String color="red"; int num=4; void run(){ system.out.println(color+""+num); } } class CarDemo{ public static void main(String[] args){ Car c=new Car(); c.color="bule"; c.num=5; c.run(); Car c1=new Car(); c1.num=8; c1.color="green"; c1.run(); } }
重点:分析上述代码在内存中的分布:
3. 成员变量和局部变量的区别:
1. 源代码中定义位置不同:
成员变量:定义在类中,在整个类中有效。
局部变量:定义在函数中,在局部范围内有效。
简单一句话:作用范围不一样,成员变量作用于整个类中,局部变量作用于函数中,或者语句中。
2. 在内存中的位置和事件不同:
生命周期不同:
成员变量:随着对象的创建的而出现在堆内存中,随着对象被回收而消失。
局部变量:随着变量所属局部区域的运行,而出现在栈内存中,随着所属区域运行结束而释放。
3. 变量使用的初始化:
成员变量:因为堆内存中都有默认初始化值,对于引用型变量默认值就是null;
局部变量:因为在栈内存中都没有默认初始化值,必须手动初始化后才可以参与运算。
4. 匿名对象:即没有名字的对象,简化书写用的。
基本使用:1. 当对对象的方法只调用一次时,可以用匿名对象来完成,这样写比较简化,如果对一个对象进行这个成员的调用,必须给这个对象起个名字;
2. 可以将匿名对象作为实际参数进行传递;一旦对对象进行多个成员操作时,必须要对对象起个名字。
public static void main(String[] args){ show(new Car()) } public static void show (Car c){ c.num=3; c.color="back"; c.run(); }
5. 面向对象三个特征:封装、继承和多态。
1.封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式,凡是面向对象必须有封装性。
特点:1. 将变化隔离; 2. 便于使用; 3. 提高复用性; 4. 提高安全性。
原则:1. 将不需要对外提供的内容都隐藏起来; 2. 把属性都隐藏,提供公共方法对其访问。
在代码中的体现:1.将成员变量都私有化,并通过共有的方法对其进行访问,这两个方法是:setXxx和getXxx;
2.只要不准备对外提供的全部都封装起来;
3. 私有仅仅是封装的一种表现形式,函数是最小的封装体,类也是封装体。
★方法需要私有吗?
public static void selectSort(){ swap(); } private void swap() { } //此处私有是因为位置置换不用提供给用户;
代码实现:
class Person{ private int age;//为了不让其他程序直接访问age属性,避免错误的数据,可以使用一个关键字来完成private私有,它是一个权限修饰符。 public void setAge() { //对外提供函数是可以控制你输入的参数。 //一个成员变量通常对应的两个方法、 if(a>130||a<0) { age=a; speak(); } else system.out.println(); } public void getAge() { return age; } void speak() { sop(); } } class PersonDemo { public static void main(String[] args) { Person p=new Person(); p.age=-20;//错误数据是因为对象直接访问age属性造成的。 p.speak(); } }
总结:凡是set开头的返回值类型是void,get开头的跟它的返回值类型一致。
6. 构造函数:用于给对象初始化的;
1.特点:1.函数名固定,与类名相同;
2.不需定义返回值类型;
3.不可以写return语句。
2.作用:给对象进行初始化;对象一建立,就会调用与之对应的构造函数对其进行初始化。
3. 小细节:当一个类中无构造函数时,系统会自动给该类加上一个空参数的构造函数;如果在该类中定义了具体的构造函数,那么系统默认的空参构造函数就没有了。
4.构造函数和一般函数的区别:
1.格式上的不同:构造函数格式为 修饰符类名(参数列表){};而一般函数格式为 修饰符 返回值类型 自定义函数名(参数列表){}
2. 运行上不同:构造函数是在对象已经建立就执行对应的构造函数,给对象进行初始化。而一般函数是在对象创建后,再被调用。
3. 作用不同:构造函数是对对应对象进行初始化的,叫做对象已建立时要做什么事情;而一般函数是给对象提供更多的功能,方便与对象的调用。
4. 调用次数不同:构造函数是对象创建时,就调用一次,因为初始化动作最先执行,只执行一次;而一般函数在对象创建后,可以被多次调用。
5.什么时候定义构造函数?
当分析事物时,该事物存在具备一些特性或者行为,那么将这些内容定义在构造函数中;如在描述人的时候,人有自己的属性姓名、年龄等,如果要一创建人类对象的时候就要对象有姓名、有年龄,这个时候就可以定 义一个带name和age参数的构造函数,来对对象进行初始化,使其一创建就有name和age。
6. 构造函数内部的初始化顺序:默认初始化>显示初始化;默认初始化始终是第一位。
7. 注意:如果构造函数中存在判断语句,可以加return语句,作用是结束语句;如果将构造函数加上void,则不再是构造函数而是一般函数。
7.构造代码块:定义在类中,是一个独立的代码块,作用是给所有对象进行初始化的,在构造函数之前执行。
和构造函数的区别:构造代码块是给所有对象初始化;而构造函数是给对应的对象初始化。
和局部代码块的区别:局部代码块是定义在函数中,用来定义变量的声明周期。
8.this关键字:看上去是用来区分成员变量和局部变量;
1.用于:当成员变量和局部变量重名的时候,为了区分这种情况我们可以使用this关键字来完成;它代表的是当前对象的引用,自己本身不是一个对象,仅仅是一个本类对象的引用。
2.应用:给人定义一个用于比较年龄是否相同的方法,代码体现如下:
总之,当定义类中功能时,该函数内部要用到该函数的对象时,这时用this来表示这个对象。class Person{ public boolean compare(Person p){ return this.age==p.age;//用到了本类对象,用this来表示。 } } class PersonCom{ public static void main(String[] args){ Person p1=new Person(20); Person p2=new Person(25); boolean b=p1.compare(p2); System.out.println(b); }
3.构造函数间的调用:构造函数中调用其他构造函数的this() 语句必须定义在构造函数的第一行,因为构造函数是用来初始化的;初始化的动作必须先执行。注意:1.this()语句只能放在构造函数的第一行,这是规则; 2. 函数中不允许两个构造函数一直循环调用; 3. 一般函数不能直接调用构造函数。如:Person(String name){ this.name=name; } Person(String name,int age){ this(name);//p(name) this.age=age; }
9.静态(static):当多个对象中存在共享数据是使用它修饰;它是修饰成员的修饰符,它所修饰的成员变量的数据被对象所共享;当成员被static修饰后,就多了一种调用方式,除了被对象调用外,还可以直接被类名调用,格式为 类名. 静态成员,即没有对象仍然可以调用。
1.静态特点:1. 静态随着类的加载而加载,随着类的消失而消失,生命周期最长;
2. 被所有对象所共享;
3.优先于对象存在;
4. 可以直接被类名调用;
2.好处:对对象的共享数据进行单独空间(方法区)的存储,节省空间,没必要每个对象中都存储一份,可以直接被类名调用。
3.弊端:生命周期过长;访问出现局限性,静态只能访问静态。
4.类变量(静态)和实例变量(非静态)的区别:
1.存储位置:类变量随着类的加载而存在于方法区中;而实例变量随着对象的创建存在于堆内存中;
2.生命周期:类变量随着类的消失而消失,生命周期最长;而实例变量随着对象的消失而消失。
5.使用注意事项:
1.静态方法只能访问静态成员,非静态的方法可以访问静态成员,也可以访问非静态成员;
2.静态方法不可以定义this,super关键字,因为this,super都代表对象的引用,而静态是优先于静态存在的;
3.主函数也是静态的,它是特殊函数,格式是固定的,能被jvm识别。
6.什么时候使用静态?因为静态是修饰成员的,所以从两方面下手:
1.成员变量:当对象中出现共享数据(值)时(注意是值共享,如人都有姓名这个属性,但姓名属性值不一样,张三、李四等,所以不能共享),该数据被静态修饰;而对象中的特有数据需定义为非静态的存储在堆内存中;
2.成员函数:当方法中没有访问到对象的特有数据时,就可以定义为静态方法,用static修饰。
7.静态代码块:
1. 特点:无法调用,随着类的加载而执行,且仅执行一次。和主函数在同一个类中,优先于主函数运行; 格式: static { 执行语句 }
2. 作用:可以给类进行初始化。3. 注意:1.若类中所有方法都是静态的,则可以私有构造函数以免创建对象浪费空间。
2. 若不希望静态变量随意修改,可以将其私有,此时再把构造函数私有,这样外部就不能对其修改,只有内部类中的方法才可以修改变量的值。
4. 对象的初始化顺序:父类静态内容>子类静态内容>父类非静态代码块>父类构造代码块>父类构造函数>子类非静态代码块>子类构造代码块>子类构造函数,代码体现如下:
过程如下:Person p=new Person()做的事:class Person { private String name; private int age; private static String country="cn"; Person(String name,int age) { this.name=name; this.age=age; } public void setName(String name) { this.name=name; } public void speak() { System.out.println(this.name+"..."+this.age); } public static void showCountry() { System.out.println("Country="+country); } } class PersonDemo { public static void main(String[] args) { Person p=new Person("lisi",21); } }
1.因为new用到了Person.class,所以会先找到Person.class文件并加载到内存中;
2.执行该类中的静态代码块,若有的话,给Person类进行初始化;
3.在堆内存中开辟开辟空间,分配内存地址;
4.在堆内存中建立对象的特有属性,并进行默认初始化;
5.对属相进行显示初始化;
6.对对象进行构造代码块初始化;
7.对对象进行构造函数初始化;
8.将内存中地址赋给栈内存中的p变量。
10. 单例设计模式:保证一个类中对象的唯一性;
想要保证唯一:1. 为了避免程序过多建立该类对象,先禁止其它程序建立该类对象;
2. 为了让其它程序可以访问到该类对象,只好在本类中自定义一个对象;
3. 为了方便其它程序对自定义对象访问,可以提供一些访问方式。
其中之一(饿汉式)代码体现:
class Single{ private Single() { } //私有化构造函数,避免创建对象 private static Single s=new Single();//自定义一个本类对象 public Single getInstance(){ //用于外界访问自定义对象 return s; } } class SingleDemo { public static void main(String[] args) { Single s=Single.getInstance(); } }
Class SingleDemo {
Public static void main(String[] args) { Student s1=Student.getStudent(); Student s2=Student.getStudent(); s1.setAge(40) s2.setAge(50); } } Class Student { private int age; private static Student s=new student(); private Student() {} public static Student getStudent() { return s; } public void setAge(int age) { this.age=age;
} public int getAge() { return age; } }
内存分析如下:得出结果为50.
首先类进入内存,将类中的方法加载进方法区中,此时Person类中还定义了一个Person类型的p并默认初始化为null,此时在堆内存中创建一个对象new Person 并对其age属性进行默认初始化值为0;并分配其内存地址值为 0x0045,并将此 地址值赋值给栈内存中的p1=0x0045,此时p1通过该地址值指向堆内存中的age.此时Person()加载进入栈内存,它里面有this 和age,this指向的当前调用该方法的对象p1.此时p1将指向堆内存中的地址值赋值给this.Person类方法通过该地址 值指 向堆内存中的实体。然后将5赋值给堆内存中的实体。此时堆内存中的age=5;然后Person方法弹栈。调用Person类的getInstance()方法加载进入栈内存,然后加地址值返回方法区中的p。此 时方法区中的Person指向堆内存中的实体。然 后弹栈。此时Person p1=Person.Instance();执行完毕,第二条语句同理。当执行完之后,p2=0x0045指向堆内存中的同一实体。P1调用Person类中的setAge的方法,对堆内存 中的实体进行赋值。此时age=40;s2调用Person类中的setAge 方法,对堆内存中的实体进行赋值。此时age=50.最后实体中的age的值为50。
模式二:懒汉式,代码体现如下:
class Single{
private Single() { } private static Single s=null; public Single getInstance(){ if(s==null)
s=new Single();
return s; } } class SingleDemo { public static void main(String[] args) { Single s=Single.getInstance(); } }
开发时,建议使用饿汉式,因为它安全。