一.概述
1.对象
Java是面向对象的。
那么什么是面向对象?
面向对象是相对面向过程而言
面向对象和面向过程都是一种思想
面向过程:强调的是功能行为
面向对象:将功能封装进对象,强调具备了功能的对象。
面向对象是基于面向过程的。
优点:
它符合人们思考习惯的思想 。而且可以将复杂的事情简单化 ,使程序员从执行者转换成了指挥者。
面向对象的特征: 封装(encapsulation)
继承(inheritance)
多态(polymorphism)
2.类
定义:类是一种抽象的数据类型,其定义为:
class 类名{}
3.类与对象的关系
使用计算机语言就是不断的在描述现实生活中的事物。 java中描述事物通过类的形式体现,类是具体事物的抽象,概念上的定义。对象即是该类事物实实在在存在的个体。如下图:
即类就是图纸 汽车就是堆内存中的对象 。
二.三大特性
1.封装
(1)简介
封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
好处: 将变化隔离。 便于使用。 提高重用性。 提高安全性。
封装原则: 将不需要对外提供的内容都隐藏起来。
把属性都隐藏,提供公共方法对其访问。
封装的一个方式:private
private :私有,权限修饰符:用于修饰类中的成员(成员变量,成员函数)。
私有只在本类中有效。
将age私有化以后,类以外即使建立了对象也不能直接访问。
但是人应该有年龄,就需要在Person类中提供对应访问age的方式。
注意:私有仅仅是封装的一种表现形式。
之所以对外提供访问方式,就因为可以在访问方式中加入逻辑判断等语句。
对访问的数据进行操作。提高代码健壮性。
该方式的使用较简单,就是在定义个类时,可以对里面变量就行私有化。私有化的成员当本类中不提供对其赋值获取的函数时(即get() set()方法),类外是无法调用的。
代码示例:
class Person{
private int age;//私有化
private String name;//私有化
public void show(){}
.....
}
(2)构造函数
对象一建立就会调用与之对应的构造函数。
构造函数的作用:可以用于给对象进行初始化。
构造函数的小细节: 当一个类中没有定义构造函数时,那么系统会默认给该类加入一个空参数的构造函数。
当在类中自定义了构造函数后,默认的构造函数就没有了。
构造函数和一般函数在写法上有不同。
在运行上也有不同:
构造函数是在对象一建立就运行。给对象初始化。
而一般方法是对象调用才执行,给是对象添加对象具备的功能。
一个对象建立,构造函数只运行一次。 而一般方法可以被该对象调用多次。
什么时候定义构造函数呢?
当分析事物时,该事物存在具备一些特性或者行为,那么将这些内容定义在构造函数中。
代码示例:
class Person{
private int age;//私有化
private String name;//私有化
Person(){}//构造函数的方法名是与类名相同的,现在这个函数是空参数的。
Person(String n){name = n}//这个就是带参数的构造函数。它与上面空参数的是可以一起存在的,方法名相同但是参数不同即:函数的重载。
public void show(){}
.....
//下面是两个私有成员的get(获取值) set(赋值)方法,以便于类外调用
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class PersonDemo
{
public static void main(String[] args)
{
//两种方式都可以获得Person对象
Person p1 = new Person();
Person p2 = new Person("lisi");
......
}
}
(3)this简介:
this:表面上区分局部变量与成员变量同名的情况。
this:代表本类的对象。
this代表它所在函数所属对象的引用。
简单说哪个对象在调用this所在的函数,this代表哪个对象。
this的应用:当定义类中功能时,该函数内部要用到调用函数的对象时,这时用this来表示这个对象,但凡本类功能内部使用了本类对象,都用this来表示。
this的调用必须是构造函数中的第一个语句。
因为构造函数是对变量的初始化,需要先执行。
(4)构造代码块:
作用:给对象进行初始化。
对象一建立就运行,优先于构造函数执行。
于构造函数的区别:构造代码块是给所有对象进行统一的初始化,而构造函数是给对应的对象初始化。
代码示例{
System.out.println(“person code run”);
}
static关键字: 用于修饰成员(成员变量和成员函数)
被修饰后的成员具备以下特点:
随着类的加载而加载
优先于对象存在 被所有对象所共享
可以直接被类名调用 :类名.静态成员。
static特点:
①随着类的加载而加载。 也就说:静态会随着类的消失而消失。说明它的生命周期最长。
②优先于的对象存在:明确一点:静态是先存在。对象是后存在的。
③被所有对象所共享
④可以直接被类名所调用。
实例变量和类变量的区别:
①存放位置。
类变量随着类的加载而存在于方法区中。
实例变量随着对象的建立而存在于堆内存中。
②生命周期:
类变量生命周期最长,随着类的消失而消失。
实例变量生命周期随着对象的消失而消失。
静态使用注意事项:
①静态方法只能访问静态成员。
非静态方法既可以访问静态也可以访问非静态。
②静态方法中不可以定义this,super关键字。
因为静态优先于对象存在。所以静态方法中不可以出现this。
③主函数是静态的。
静态有利有弊:
利处:对对象的共享数据进行单独空间的存储,节省空间。没有必要每一个对象中都存储一份。可以直接被类名调用。
弊端:生命周期过长,访问出现局限性。(静态虽好,只能访问静态。)
代码示例:
class Person
{
String name;//成员变量,实例变量。
static String country = "CN";//静态的成员变量,类变量。
public static void show()
{
System.out.println("::::");
this.haha();
}
public void haha()
{}
}
class StaticDemo
{
public static void main(String[] args)
{
Person p = new Person();
Person.show(); //使用类名调用静态函数。
}
}
(6)静态代码块:
静态代码块随着类的加载而执行(StaticDemo s = null 时不是加载),只执行一次。
格式:
static
{
静态代码块的执行语句。
}
当调用方法时,如果该方法的类里包含静态代码块,那么先执行静态代码块,再执行该类调用的方法。
new p=new Person所进行的操作及其顺序。
1.先找到Perpon.class 所以会先找到Perpon.class文件 并且加载到内存中。
2.执行static代码块,如果有的话,给Person.class进行初始化
3. 在对内存开辟空间,分配内存地址
4.在堆内存中建立对象的你特有属性,并且进行默认初始化。
5.对属性进行显示初始化
6.对对象进行构造代码块初始化。
7.对对象进行对应的构造函数初始化。
8.将内存地址付给栈内存的变量。
在new对象时,构造代码块优先构造方法执行
静态块优先于主方法的执行,静态块优先于构造方法的执行,而且只执行一次!
加载,是将类文件中的一行行内容存放到了内存当中,并不会执行任何语句。---->加载时期,即使有输出语句也不会执行。
静态代码块、构造代码块和构造函数的区别:
静态代码块:用于给类初始化,类加载时就会被加载执行,只加载一次。
构造代码块:用于给对象初始化的。只要建立对象该部分就会被执行,且优先于构造函数。
构造函数: 给对应对象初始化的,建立对象时,选择相应的构造函数初始化对象。
创建对象时,三者被加载执行顺序:静态代码块--->构造代码块--->构造函数
(7)单例设计模式
单例设计模式:解决一个类在内存中只存在一个对象。
保证唯一性:
1.先控制禁止其他程序建立该对象。
2.还为了其他程序可以为访问该类对象,在本类中自定义一个对象。
3.为了方便其他其程序对自定义对象的访问,可以对外提供一些访问方式。
对应操作:
1.将构造函数私有化。
2.在本类中创建一个本类对象(私有并且static)。
3.提供一个方法可以获取到该类对象。
构造函数私有化:
私有构造函数只能在函数内部调用,外部不能实例化,所以私有构造函数可以防止该类在外部被实例化。
单例化有两种方式:饿汉式和懒汉式
饿汉式:先初始化对象 ,A类一进入内存便建立一个对象
class A {
private A(){}
private static A s = new A();
public static A getInstance(){
return s;
}
}
懒汉式:对象是方法调用时,才初始化:
class A {
private static A s = null;
private A(){}
public static A getInstance(){
if(s==null)
s = new A();
return s;
}
}
补充(多线程部分内容):
单例模式就是为了使用这个对象,那么一般使用饿汉式,且安全。
单例模式中饿汉式较为安全,因为有一个if(s = null)
synchronized 同步。懒汉式加入以后比较慢。
if(s == null){
synchronized(A.class){
if(s == null)
{
s = new A();
}
}
}