一、什么是面向对象?
面向对象是一种基于面向过程的编程思想。
面对对象是把功能(方法)封装进了对象,强调的是对象具备解决问题的功能,突出的是对象的行为。
我理解的面对对象,遇到需要解决的问题就找个能解决问题的对象,如果没有的话干脆自己创造个对象来解决遇到的问题,有了对象遇到它能解决问题就都交给它,方便。
二、面向对象的举例
在Java高手眼中,万物皆对象。(这是一种境界)
面向对象的三个特征:封装,继承,多态。
在以后的开发过程中就是找对象用,没有对象的话,咱们就自己创建对象。
我们与对象的关系就是:找对象、用对象、创建对象、维护与对象之间的关系。
总的来说任何一件事物都是一个对象,都有自己的属性和行为。比如说学生,学生的属性有姓名、年龄、年级等,行为就是学习,这就是一个具体的对象,而把一类对象 的共性给抽取出来,比如共同的属性姓名和年龄、共同的行为学习,组成一个集合就是一个类。类是对象的集合,是对对象的描述,而对象又是类的具体化。
面对对象从字面上我们可以看出是我们要面对对象,就比如说我需要吃饭,就找一个会做饭的对象,告诉他给我来份饭,然后给我把饭端上来就行上了,至于他怎么做的我不用管,只知道你会做饭,我就用这个会做饭的功能,知道这个对象里有做饭的方法,我直接可以可以拿来用就行了。面对对象强调的是是对象的行为,具体点就是我要的是结果,过程全在对象里完成,我用你做事去了,你给我一个结果就OK,不管你过程多复杂,我只要结果,其他跟我没关系。
三、类与对象的关系
类可以理解为一类的东西,是一个集合,对象是一个具体的事物。把对象中共性的东西抽取出来就是一个类。类可以理解为一张图纸,而对象就是根据图纸造出来的实物。
我们可以理解为类就是对对象的描述,而对象就是类描述的具体个体。
具体举例:
描述学生类
学生的属性:年龄、姓名、性别
学生的行为:学习
其实定义类,就是在描述事物。类中的属性和行为共同成为类中的成员。类中不必有主函数,不必保证独立运行,程序中只要保证有一个主函数入口调用类就行。
类的具体代码实现:
class ClassDemo
{
public static void main(String[] args)
{
//创建一个学生对象
Student sd = new Student();
//调用学生对象中的学习方法
sd.study();
}
}
//描述一个学生类
class Student
{
//描述学生类的属性 有姓名 年龄 性别 这都是一个学生必须具备的属性
String name="格子";
int age=20;
String sex="男";
//描述学生类的行为 学生的行为被描述成方法 就是学习 study
void study()
{
System.out.println("这是一个具体的对象");
}
}
四、成员变量和局部变量
类的关键字是class,定义一个类就是class加上类的名字然后用一个{}括起来,{}存放的是就是属性和行为(成员变量和成员方法)。比如说定义一个叫people的类,他里边的属性有年龄、姓名、性别、行为是吃饭,就可以如下定义
class People
{
//描述年龄
int age ;
//描述姓名
String name ;
//描述性别
String sex ;
//描述吃饭
void eat()
{
System.out.println("我的行为就是吃饭!!!");
}
}
其中类的名字就是people,他有如下属性:age name sex和一个eat的方法。想要将类实例化就是people p = new people();这样就会产生一个具体的对象了,这个对象也具备这些属性和行为,对象实例化后我们就能操作对象了,比如果给他一个20的年龄,可以如下操作:p.age=20;这样我们就给对象中age这个属性给初始化了。
对象中操作都靠 对象名.成员 操作。
所谓的成员变量对应的就是类中的属性,因为在具体化成对象后属性是个变化的值,所以是个变量,而成员方法就是类中具备的行为,也就是的方法(函数)。
成员变量和局部变量区别:
作用范围:
成员变量作用于整个类中。
局部变量变量作用于函数中,或者语句中。
在内存中的位置:
成员变量:在堆内存中,因为对象的存在,才在内存中存在。
局部变量:存在栈内存中。
成员变量:有具体的初始化值。
局部变量:没有具体的初始化值。
五、匿名对象
匿名对象,顾名思义就是没有名字的对象。
匿名对象就是初始化对象对象的简写。
使用方法是: new people();
匿名对象也可以创建一个实际的对象。
匿名对象可以作为实际参数传递。
匿名对象只能作用一次,在运行完一次之后就会被系统当作垃圾回收。
六、封装
所谓的封装就是对外隐藏对象的属性和实际细节,只对外提供公共访问的方式。
封装的好处:
1.将变化隔离;
2.便于使用。
3.提高重用性。
4.提高安全性。
封装的原则:
将不需要对外提供的内容都隐藏起来。
把属性都隐藏,提供公共方法对其访问。
关键字:private(私有)
1.用于修饰成员变量和成员方法。
2.被修饰的内容只能在本类中访问,在其他类中是不可以被访问的。
3.被private修饰的成员一般要对外提供接口,也就是说一般私有成员都要对外提供两个方法,一个是设置成员变量的值就是set开头,一个是得到成员变量的值用get开头,这是规范格式。
4.封装的方式有很多种,只要不被外类访问就可以,private是设置最小权限,是比较常用的封装的一种体现,千万不要以为封装就是private。
class PrivateDemo
{
public static void main(String[] args)
{
Student su = new Student();
su.setage(20);
su.study();
}
}
class Student
{
//将年龄私有
private int age =20;
//对外提供访问age的方法
public void setage(int a)
{
if(a<130)
age = a;
else
System.out.println("输入非法");
}
//对外提供得到age方法
public int getage()
{
return age;
}
private String name = "gezi";
public void setname(String n)
{
name=n;
}
public String getname()
{
return name;
}
void study()
{
System.out.println("age="+age);
}
}
之所以对外提供访问的接口,是控制传入的值,我们可以在对外提供的方法中,来对输入的值进行筛选,只要我们需要的值,这也是封装的好处,可以提高 安全性。
六、构造函数
什么是构造函数?
构造函数也是函数的一种,是用来给给对象初始化的,给对象赋初始化值,所有的对象必须初始化后才能被建立。一个对象如果没有构造函数,系统就会默认一个空参的构造函数,如果已经定义构造函数,系统就不会默认建立构造函数。
构造函数有什么作用?
构造函数是用来给对象初始化的,主要用于描述一些事物时,事物本身已经具备了一些内容,而这些内容就会通过构造函数来传递,在对象初始化的时候,就把这些值直接赋给对象。
构造函数有什么特点?
1. 构造函数必须为本类名。
2. 构造函数没有返回值类型。
3. 构造函数可以有多个,以重载的形式存在。
4. 构造函数没有具体的返回值。
5. 定义构造函数时一般用public修饰,以保证在程序任何位置创建对象。
构造函数与一般函数有什么不同?
构造函数:对象创建时,就会调用与之对应的构造函数,给对象进行默认初始化。
一般函数:对象创建后,需要函数功能时才调用。(函数只有被调用才执行)
构造函数:对象创建时,只调用一次,。
一般函数:对象创建后,可以被重复调用多次。
什么时候需要定义构造函数?
当事物在被描述时,该事物已存在就会存在一些属性,这些内容就需要定义在构造函数中,构造函数可以以重载的形式存在多个,系统会针对传递的参数,寻找相对应的构造函数来初始化对象。
构造函数示例:
class StructDemo
{
public static void main(String[] args)
{
//创建时传递参数
Student su =new Student(20,"gezi");
su.study();
}
}
class Student
{
{
System.out.println("这里是构造函数");
}
//空参的构造函数
public Student(){}
//自定义的构造函数
public Student(int age,String name)
{
this.age = age;
this.name = name;
}
private int age;
private String name;
//对外提供访问age的方法
public void setage(int a)
{
if(a<130)
age = a;
else
System.out.println("输入非法");
}
//对外提供得到age方法
public int getage()
{
return age;
}
public void setname(String n)
{
name=n;
}
public String getname()
{
return name;
}
void study()
{
System.out.println("age="+age+"\n"+"name="+name);
}
}
七、构造代码块
什么是构造代码块?
构造代码块也是用来初始化对象的,而且是所有对象的共性内容。不同于构造函数的是构造代码块是给所有对象统一初始化,而且优先于构造函数执行。
需要注意的的是,构造代码块只在对象创建时运行,这是与构造函数的相同之处,并且在执行完构造代码块之后才会继续执行构造代码块。
格式:
//构造代码块没有名字,只在一个{}里定义,创建对象时会自动运行。
{
代码块
}
具体的程序就不做演示了,可以参考构造函数的程序。
八、关键字this
this关键字的特点:
this代表其所在函数所属对象的引用,其实就是this代表本类对象的引用。
this使用的方法:
在函数需要调用该函数的对象时,用this表示该对象。
在成员变量和局部变量重名时,用this来区分。
this代表的对象都是当前对象,换而言之就是当前对象的一个代名词或是引用。
最重要的是:哪个对象调用了this所在的函数,那么this就代表这个对象。
this也可以在构造函数里被调用,但是只能在构造函数的第一行,而且构造函数调用的时候必须用this。
在本类中this可以省略,但是不在本类中时必须用this以区分。
如果传入的参数与本类中成员重名时,必须用this区分。
this使用示范:
/*
需求:判断两个人是不是同龄人
*/
class ThisDemo
{
public static void main(String[] args)
{
Person p = new Person();
p.setage(20);
Person pe = new Person();
pe.setage(22);
//调用比较方法 并存储
boolean b = p.judge(pe);
//打印结果
System.out.println(b);
}
}
class Person
{
private int age;
private String name;
//对外提供访问age的方法
public void setage(int age)
{
if(age<130)
this.age = age;
else
System.out.println("输入非法");
}
//对外提供得到age方法
public int getage()
{
return age;
}
public void setname(String name)
{
this.name=name;
}
public String getname()
{
return name;
}
//判断是否同龄
public boolean judge(Person p)
{
return this.age==p.age;
}
}
八、关键字 static
static有什么作用?
static是一个修饰符,可以修饰类中的成员(成员变量和成员方法);成员被修饰后被称为静态成员。
成员一旦被static修饰后具有如下特点:
1.随着类的加载而加载。
2.优先于对象存在。
3.被所有对象共享。
4.增加一种调用方式。即用类名可直接调用其成员,格式为:类名.静态成员。
static有什么特性?
1. 是一个修饰符关键字,用于修饰类中的成员。
2. 随着类的加载而加载,因此优先于对象存在。
3. 为static修饰的成员添加一种调用方式,即类名.静态成员直接可以调用。
4. static修饰后的数据为共享数据,可以被所有对象访问。
静态成员变量和分静态成员变量有什么区别?
1. 生命周期不同
静态成员变量随着类的加载而加载,也随着类的消失而消失,因此会随类的存在一直存在,生命周期最长。
非静态成员随着对象的创建而创建,随着对象的消失而消失,生命周期相对较短。
2. 调用方式不同
静态成员变量不但可以被对象调用,还能直接被类调用。
非静态成员变量只能被对象调用。
3. 内存存储位置不同
静态成员变量存储在内存的方法区。
非静态成员变量存储在内存的堆内存里。
另外静态成员变量也被称作类变量,而非成员变量被称作实例变量。
static什么时候被使用?
被static修饰后,数据就会被共享,所以当对象存在共同的数据时就可以使用static修饰来节省内存空间。
被static修饰的成员包括成员变量和成员方法,所要分为两种情景来使用。
什么时候成员变量需要被static修饰?
当对象存在可以共享的成员变量时可以用static修饰。比如在student类中,学校是对象所共有的成员变量,可以被static修饰,其余学号、姓名等变量属于特有成员变量,不可以被static修饰。
什么时候成员方法需要被static修饰?
当成员方法没有访问到非静态成员变量或只访问静态变量时即可用static修饰为静态方法。
静态成员的有什么利弊?
静态成员的好处:
静态成员被修饰后会在内存中单独开辟一块空间用来存储数据共所有对象访 问,不会在随着每个对象的创建而创建,因此可以节省内存空间的使用。
静态成员的弊端:
静态成员存在局限性。因为静态成员是随着类的加载而加载,生命周期过长。而且在静态成员方法调用中只能调用静态的成员,非静态成员无法被调用。
Static的应用:
class StaticDemo
{
public static void main(String[] args)
{
//直接访问类中的静态成员
Student.school ="xx学校";
//直接访问类中的静态方法
Student.study();
}
}
class Student
{
public Student(){}
public Student(String name)
{
this.name=name;
}
private int age;
private String name;
//学校是学生的共有数据 可以被共享
public static String school ;
public void setage(int age)
{
if(age<130)
this.age = age;
else
System.out.println("输入非法");
}
public int getage()
{
return age;
}
public void setname(String name)
{
this.name=name;
}
public String getname()
{
return name;
}
//被static修饰后的方法只能访问静态成员
public static void study()
{
System.out.println("这是static静态方法"+school);
}
}
九、主函数的格式
public static void main(String[] args)
主函数:是一个特殊的函数。作为程序的入口,可以被jvm调用。
主函数的定义:
public:代表着该函数访问权限是最大的。
static:代表主函数随着类的加载就已经存在了。
void:主函数没有具体的返回值。
main:不是关键字,但是是一个特殊的单词,可以被jvm识别。
(String[] arr):函数的参数,参数类型是一个数组,该数组中的元素是字符串。字符串类型的数组。
主函数是固定格式的:能被jvm识别。
jvm在调用主函数时,传入的是newString[0];
主函数mian验证代码:
class MainDemo
{
public static void main(String[] args)
{
String[] arr ={"你好","我是","main函数"};
MainTest.main(arr);
//证实主函数确实传入是一个数组
//System.out.println(args.length);
}
}
class MainTest
{
//向主函数传递参数并打印长度
public static void main(String[] args)
{
System.out.print("[");
for(int x=0; x<args.length; x++)
{
if(x!=args.length-1)
System.out.print(args[x]+",");
else
System.out.print(args[x]);
}
System.out.println("]");
System.out.print("args-length="+args.length);
}
}
十、静态代码块
静态代码块的格式:
Static
{
静态代码块执行语句
}
静态代码块的特点;
随着类的加载而执行,只执行一次。
优先于主函数运行,用于初始化类。
class StaticDemo2
{
//验证是否优先于主函数运行
static
{
System.out.println("Hi,我是静态代码块");
}
public static void main(String[] args)
{
StaticTest st = new StaticTest();
}
}
//验证静态代码块、代码块、构造函数的执行顺序
class StaticTest
{
static
{
System.out.println("Hi,我是静态代码块");
}
{
System.out.println("Hi,我是代码块");
}
public StaticTest()
{
System.out.println("Hi,我是构造函数");
}
}
十一、对象初始化过程
静态代码块——>主函数——>构造代码块——>构造函数
试描述创建对象时都发生了什么?
class Demo
{
public static void main(String[] args)
{
Student stu=new Student("lisi",20);
stu.study();
}
}
class Student
{
static
{
System.out.println("这是静态构造代码块");
}
{
System.out.println("这是构造代码块");
}
Student(){}
Student(String name)
{
this.name=name;
}
Student(String name,int age)
{
this.name=name;
this.age=age;
System.out.println("这是构造函数");
}
private String name ;
public void setname(String name)
{
this.name=name;
}
public String getname()
{
return name;
}
private int age;
public void setage(int age)
{
this.age=age;
}
public int getage()
{
return age;
}
private static String school = "xx学校";
void study()
{
System.out.println("name="+name+"\t"+"age="+age+"\t"+"school="+school);
}
}
/*
student stu=new student("lisi",20);
该句话都做了什么事情?
1,因为new用到了 student.class.所以会先找到 student.class文件并加载到内存中。
2,执行该类中的static代码块,如果有的话,给 student.class类进行初始化。
3,在堆内存中开辟空间,分配内存地址。
4,在堆内存中建立对象的特有属性。并进行默认初始化。
5,对属性进行显示初始化。
6,对对象进行构造代码块初始化。
7,对对象进行对应的构造函数初始化。
8,将内存地址付给栈内存中的p变量。
*/
十二、面对对象的单例设计模式
什么是设计模式?
设计模式就是人们在设计代码过程中,总结的一些解决一类方法行之有效的方法。在Java中有23种常见的设计模式,当然,我们也可以定义自己的设计模式。
Java设计模式之对象单例设计
什么时候会用到对象的单例设计?
比如说程序的配置文件,配置文件只能有一个,供程序启动时读取配置文件的信息,所以我们就需要让对象唯一化,也就是说只能有一个对象?
怎么实现对象唯一化?
思路:
1. 将构造函数私有化。
2. 类中创建一个本类的对象。
3. 对外提供一个访问本类对象的公共方法或接口。
步骤:
1. 将构造函数私有化。
2. 在类中创建一个本类对象。
3. 提供一个方法可以获取到该对象。
需要注意的是,在类中对于事物该怎么描述,还怎么描述。
当需要将该事物的对象保证在内存中唯一时,就将以上的三步加上即可。
单例设计模式的简单示例:
class SingleDemo
{
public static void main(String[] args)
{
//利用对外提供的方法创建对象
Student s1 = Student.getInstance();
//利用对外提供的方法创建第二个对象
Student s2 = Student.getInstance();
//设置s1对象
s1.setage(20);
//获取s2对象的年龄 验证对象是否唯一
System.out.println(s2.getage());
}
}
class Student
{
//私有化构造函数
private Student(){}
//创建本类对象
private static Student s = new Student();
//对外提供访问方法
public static Student getInstance()
{
return s;
}
private int age;
private String name;
public void setage(int age)
{
if(age<130)
this.age = age;
else
System.out.println("输入非法");
}
public int getage()
{
return age;
}
public void setname(String name)
{
this.name=name;
}
public String getname()
{
return name;
}
}
单例设计模式之懒汉式
所谓懒汉式,就是让方法被调用是才创建对象,也称作对象延时加载,比较省内存。
懒汉式一般只在面试中考到,实际的设计中,不会采用此方式。
所谓的对象延迟加载,就是让类先加载到方法区内从中,只有方法被调用时才创建对象。
class Single
{
private static Single s = null;
private Single(){}
public static Single getInstance()
{
if(s==null)
{//给程序加锁
synchronized(Single.class)
{
if(s==null)
s = new Single();
}
}
return s;
}
单例设计模式之饿汉式
所谓饿汉式,就是不管方法有没有被调用,先把对象穿件完毕,相对消耗内存,但是代码简单,不易出错。
饿汉式在类一加载的时候就会自动创建对象,不管有没有被调用。
class Single
{
private static Single s = new Single();
private Single(){}
public static Single getInstance()
{
return s;
}
}
两种模式的利弊
懒汉式
主要是在面试中会用到,因为这里会应用到多线程等问题,涉及的知识点会比较全面。
最大的好处节省内存空间。
代码繁多,容易出错。
饿汉式
在实际开发中,一般都会使用饿汉式,因为代码简单,不易出现安全问题,但会多耗费一点内存。
最后需要注意的是当遇到需要对象单一化设计的时候,直接添加这两种模式的代码即可。