面向对象的概念
举例:大象装进冰箱。
面向过程
步骤:打开冰箱--存储大象--关上冰箱。对于面向过程思想,强调的是过程(动作)。
代表语言:C语言面向对象
步骤:冰箱打开--冰箱存储--冰箱关闭(只用找到冰箱即可)。对于面向对象思想,强调的是对象(实体)。
特点:
1、面向对象是一种常见的思想,符合人们的思考习惯
2、面向对象的出现,将复杂的问题简单化(放在生活中,即是特定的事交给特定的人做)
- 面向对象让曾经在过程中的执行者,变成了对象中的指挥者
特征:封装、继承、多态(如果未体现这三个特征,就不能说运用了面向对象的思想 )
代表语言:C++,Java,C#
举例:人开门
两个对象:人和门(名词体现法),开门的方法应该写在门中(门最清楚打开门这个动作)。
类与对象的关系
类:用Java语言对现实生活中的事物进行描述,通常只关注属性和行为这两方面。定义类其实就是在定义类中的成员——成员:成员变量<-->属性,成员函数<-->行为。
对象:该类事物的实例,在Java中通过new
关键字来创建的。对象的出现,是为了封装数据(类的每个实例,都有自己特有的数据)。
成员变量&局部变量
成员变量和局部变量的区别:
- 作用范围:成员变量定义在类中,整个类都可访问;局部变量定义在函数、语句、局部代码块中,只在所属的区域有效。
- 存放位置:成员变量存在于堆内存的对象中;局部变量存在于栈内存的方法中。
- 生命周期:成员变量随着对象的创建而存在,随着对象的消失而消失;局部变量随着所属区域的执行而存在,随着所属区域的结束而释放。
- 初始化值:成员变量都有默认初始化值;局部变量没有默认初始化值 。
匿名对象
Example1:当对象对方法仅调用一次时,可简化成匿名对象
Car c = new Car();
c.run();
//可简写为
new Car().run();
Example2:匿名对象可以作为实际参数进行传递
Car c1 = new Car();
show(c1);
//可简写为
show(new Car());
基本数据类型/引用数据类型参数传递
封装
概念:隐藏对象的属性和实现细节,仅对外提供公共访问方式。
好处:将变化隔离;便于使用;提高重用性;提高安全性。
原则:将不需要对外提供的内容都隐藏起来;把属性都隐藏,提供公共方法对其访问。
private(私有)关键字
- 是一个权限修饰符
- 用于修饰成员(成员变量和成员函数)
- 被私有化的成员只在本类中有效
将成员变量私有化,对外提供对应的get/set方法对其进行访问。提高对数据访问的安全性。
封装与私有的区别
- 私有是封装,封装不是私有。
- 私有仅仅是封装的一种体现而已。封装是面向对象的一种特征,隐藏实现的细节,但隐藏细节不代表只有私有能做到,只要能做到对方访问不到就能实现封装。(在Java中,最小的封装体是函数,只要知道函数的功能(需要的未知内容,返回值是什么 ))。
构造函数
概念:构建创造对象时调用的函数。
特点:函数名与类名相同;不用定义返回值类型。
作用:给对象进行初始化。
什么时候定义构造函数:在描述事物时,该事物已存在就具备的一些内容,这些内容都定义在构造函数中。
一般函数与构造函数的区别:
- 构造函数:对象创建时,就会调用与之对应的构造函数,对对象进行初始化。
一般函数:对象创建后,需要函数功能就调用一次。 - 构造函数:对象创建时,会调用且只调用一次。
一般函数:对象创建后,可以被调用多次。
public static void main(String[] args)
{
Person p = new Person();
p.Person();//错误写法
p.speak();
p.speak();
}
注意:默认构造函数的特点;多个构造函数是以重载的形式存在的。
默认构造函数:
创建对象必须要通过构造函数初始化。
- 一个类中如果没有定义过构造函数,那么该类中会有一个默认的空参数构造函数,
class Demo{}
在编译成Demo.class文件时会自动创建一个成员Demo(){}
。 - 如果在类中定义了指定的构造函数,那么类中的默认构造函数就没有了。
重载:一个类中可以有多个不同的构造函数,给对象不同的初始化,多个构造函数在类中是以重载的形式来体现的,重载的特点为方法名相同,方法参数(参数个数、参数类型)不一样。
内存图解(构造函数会进栈):
Example1
class Person
{
String name;
int age;
public Person()
{
name = "旺财";
age = 1;
speak(); //可调用
}
public void speak()
{
Person(); //错误写法,如果要调用,需写成new Person();
System.out.println(name + ":" + age);
}
}
Example2:构造函数中可以写return
,但并不常用
class Person
{
String name;
int age;
public Person(String n, int a)
{
if(a < 0) return;
name = n;
age = a;
}
}
this关键字
概念:代表当前对象。this就是所在函数所属对象的引用。简单说:哪个对象调用了this所在的函数,this就代表哪个对象。
什么时候使用this关键字:
当在函数内需要用到调用该函数的对象时,就用this。
当成员变量和局部变量重名,可以用关键字this来区分。
用于在构造函数中调用其他构造函数。(注意:只能定义在构造函数的第一行,因为初始化动作要先执行)
内存图解:
Example1-1:当前构造函数调用其他构造函数--正确写法
public class Person
{
private String name;
private int age;
Person(String name)
{
this.name = name;
}
Person(String name,int age)
{
/*调用Person(String name){...}的构造函数,注意不能写为this.Person(name),因为构造函数不能通过对象来调用,也不能写为Person(name),因为这个实际上就是this.Person(name)的省略形式*/
this(name);
this.age = age;
}
}
Example1-2:当前构造函数调用其他构造函数--错误写法
public class Person
{
private String name;
private int age;
Person(String name)
{
this.name = name;
}
Person(String name,int age)
{
this.age = age;
this(name);
}
}
编译错误:对this的调用必须是构造函数的第一个语句。
static关键字
定义:static是一个修饰符,用于修饰成员(成员变量和成员函数)
class Person
{
String name; //对象所特有的数据,成员变量(实例变量)
static String country = "CN"; //静态变量(类变量)
}
被static修饰的成员的特点:
- 随着类的加载而存在
- 优先于对象存在
- 被所有对象所共享
- 可以直接被类名调用(也能被对象调用)
成员变量和静态变量的区别:
两个变量的生命周期不同
成员变量随着对象的创建而存在,随着对象的被回收而释放。
静态变量随着类的加载而存在,随着类的消失而消失。调用方式不同
成员变量只能被对象调用。
静态变量可以被对象和类名调用。数据存储位置不同
成员变量数据存储在堆内存的对象中,所以也叫对象的特有数据。
静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据。
使用的注意事项:
- 静态方法在访问本类的成员时,只能访问静态成员(非静态方法即可访问静态成员,又可访问非静态成员)
- 静态方法中不可以写this,super关键字
- 主函数是静态的
Example1:在静态方法中可通过对象访问非静态方法
class StaticDemo
{
int num = 4;
static int data = 10;
public static void main(String[] args)
{
new StaticDemo().show();
//或 StaticDemo sd = new StaticDemo(); sd.show();
}
public void show()
{
System.out.println(num); //实际上是this.num
System.out.println(data);//实际上是StaticDemo.data
}
}
static的应用——主函数的特殊之处
public static void main(String[] args)
格式固定;被JVM所识别和调用。
-
public
:权限必须最大 -
static
:不需要对象,直接用主函数所属类名调用即可 -
void
:主函数没有具体的返回值( 不然..难道返回给虚拟机?) -
main
:函数名,不是关键字,只是一个jvm识别的固定的名字 -
String[] args
:主函数的参数列表,字符串类型数组
默认情况下传入的值为一个空数组,若要传值,可以通过:
javac 类名
java 类名 XX XX ...(字符串参数)
注意:
class MainDemo
{
public static void main(String[] args)
{
...
}
public static void main(int x) //函数的重载而已,这样写不会报错
{
...
}
}
内存图解
- 执行java StaticDemo2后,会开辟空间(栈、堆、方法区(分为非静态区和静态区(存储静态成员))),栈是运行区,方法区是代码置放区。
- 非静态区和静态区中的方法是所有该类的对象都具有的功能,这些对象唯一的区别是封装的数据不一样。
- 当执行main方法的第一行时,加载Person类,在classpath路径下找是否有Person.class文件,若没有设置classpath,则在当前目录下找,找到后会把Person.class文件加载进内存。
静态什么时候使用?
静态变量
当对象所具备的成员变量的值都是相同的,那么这个成员就需要被静态修饰;如果是不同的,那就是对象的特有数据,必须存储在对象中,是非静态的。-
静态函数
函数是否用静态修饰,只参考一点——该函数功能是否需要访问到对象的特有数据(即非静态的成员变量),如果需要,该功能就是非静态的;如果不需要,该功能就是静态的,当然也可以将其定义为非静态,但是非静态需要被对象调用,而仅创建对象调用非静态的没有访问特有数据的方法,该对象的创建没有意义,会造成堆空间的浪费。class Demo { int age; static int num = 9; Demo(int age) { this.age = age; } public static void speak() { System.out.println("hahaha"); } } class StaticDemo { public static void main(String[] args) { //Demo d = new Demo(30); //d.speak(); Demo.speak(); } }
静态代码块
特点:随着类的加载而执行,而且只执行一次。
作用:用于给类进行初始化。(构造函数是给对象初始化的,注意有的类可能不需要对象(如,所有的函数都是静态的))
class StaticCode
{
static int num; //在此处也可以赋值,即static int num = 10,但在此处只能进行一次赋值动作,而在静态代码块里还能对其进行更多的处理
static
{
num = 10;
num *= 3;
System.out.println("hahaha");
}
static void show()
{
System.out.println(num);
}
}
class StaticCodeDemo
{
public static void main(String[] args)
{
//new StaticCode().show();
//new StaticCode().show();
StaticCode.show();
}
}
一般会用静态代码块对类进行初始化的,那么在这个类中,全是静态成员。
构造代码块
类中的独立代码块。
构造代码块:可以给所有对象进行初始化,具有通用性
构造函数:给对应的对象(调用该构造函数的对象)进行针对性的初始化。
构造代码块比构造函数先执行。
class Person
{
private String name;
{
cry();
}
Person()
{
name = "baby";
// cry();
}
Person(String name)
{
this.name = name;
// cry();
}
public void cry()
{
System.out.println("哇哇");
}
public void speak()
{
System.out.println("name:"+name);
}
static void show()
{
System.out.println("show run");
}
}
class StaticCodeDemo
{
public static void main(String[] arg)
{
Person p1 = new Person();
p1.speak();
Person p2 = new Person();
p2.speak();
new Person();
//以上会输出三遍“哇哇”
Person.show(); //不会输出“哇哇”,即不会执行构造代码块中的内容
}
}
不允许其他类创建某类的对象
class ArrayTool
{
private ArrayTool(){}//该类中的方法都是静态的,所以该类是不需要创建对象的;为了保证不让其它类创建该类对象,可以将构造函数私有化
public static int getMax(int[] arr)
{
...
}
public static void selectSort(int[] arr)
{
...
}
}