技能目标:
1.掌握类的定义和对象的创建
2.掌握方法及方法重载
3.掌握构造方法及重载
4.理解封装的原理
5.掌握包的使用
6.会使用访问修饰符
7.会使用方法重载
5.1.1面向对象的基本概念
1.面向对象
Java语言是一种面向对象的语言。要使用Java进行面向对象的编程,首先要建立面向对象的思想。面向对象是一种直观而且程序结构简单的程序设计方法,它比较符合人类认识现实世界的思维方式。其基本思想是把问题看成若干个对象组成,这些对象之间是独立的,但又可以相互配合、连接和协调,从而共同完成整个程序要实现的任务和功能。
面向对象的三大特征:封装、继承、多态
2.对象
对象是用来描述客观事物的一个实体。用面向对象的方法解决问题,要对现实世界中的对象进行分析与归纳,找出哪些对象与要解决的问题是关联的。例:奥迪跑车、宝马跑车、奔驰轿车、保时捷跑车,虽然这几个跑车都是对象,但是他们之间具有不同的特征。具体来讲就是品牌不同、价格不同、性能不同等。
3.类
刚才的几个跑车对象之间具有一些共同的特征,如都有轮子、门等:还有一些共同的行为,即能发动,能加速,能制动等,把这些共同的特征和共同的行为组织到一个单元中,就得到类
类是具有相同属性和方法的一组对象的集合。类定义了对象将会拥有的特征(属性)和行为(方法)。
类与对象的关系就如同模具和用整个模具制作出的物品之间的关系。一个类给出它的全部对象的一个统一的定义,而它的每个对象则是符合这种定义的一个实体。因此类和对象的关系就是抽象和具体的关系。类是多个对象进行综合的抽象的结果,是实体对象的概念模型,而一个对象是一个类的实例。 如:我我定义一个人类,他(她)的属性有身高,年龄,体重。我在定义方法,他在哪里上学. (后文解释)
第一个例子:后文陆续以此例子来解释
建一个类:人类Person(首字母大写)
public class Person {
public String name; //姓名属性
public int age; //年龄属性
public int peso; //体重属性
public void output (){ //定义一个方法输出
System.out.println("姓名:"+name+" 年龄:"+age+" 体重:"+peso);
}
public void school(String school){ //一个学校方法
System.out.println(name+"的学校是:"+school);
}
}
建一个对象(实例化)
public class Text1 {
public static void main(String[] args) {
Person person1=new Person();//对象名为person1,也就是实例了
person1.name="小明";
person1.age=19;
person1.peso=88;
person1.output();
person1.school("合肥十中");
}
}
结果:
姓名:小明 年龄:19 体重:88
小明的学校是:合肥十中
5.1.2定义类
面向对象设计的过程就是抽象的过程,一般分为3步来完成。
(1).发现类,类定义了对象将会拥有的特征(属性)和行为(方法)
(2).发现类的属性,对象所拥有的静态特征在类中表示时称为类的属性
(3).发现类的方法,对象执行的操作称为类的方法
1.定义类
首先定义“人” 的类
定义类的语法格式如下。
[访问修饰符] class 类名{
//省略类的内部具体的代码
}
1).访问修饰符如public、private、等是可选的,其具体含义后续详讲
2).class声明类的关键字
3).按照命名规范,类名首字母大写
示例1:
定义一个“人”类。
2.属性
Java中的类的内部主要包含属性和方法。对象所拥有的特征在类中表示时称为类的属性。
定义属性的语法格式如下。
[访问修饰符] 数据类型 属性名:
1.访问修饰符是可以选的
2.除了访问修饰符之外,其他的语法和声明变量类似
属性在测试类中赋值
Person person1=new Person();
person1.name="小明";
person1.age=19;
person1.peso=88;
------------------------
输出可以直接用
System.out.println(person1.age);
也可以用调用person1.output();方法
示例2:
创建“人”类,并为“人”类田间相应的属性
分析如下:
人都有姓名,体重和年龄,因此这3个特征就可以称为“人”类的属性
(如上图)
3.方法
对象执行操作的行为称为类的方法,例如,除了上个例子的学校
人还有有工作的行为,因此“工作”就是“人”类的一个方法
“人”类还有很多方法,如吃、喝、睡觉等
定义方法的语法格式:
[访问修饰符] 返回类型 方法名称(参数类型 参数名1,参数类型 参数名2,...){
//...省略方法体代码
}
1)访问修饰符是可选的
2)返回类型可以是void,在定义方法时,返回类型为void时标明没有返回值,方法体中不必使用"return"
关键字返回具体数据,但是可以使用"return"关键字退出方法
3)返回类型如果不是void,那么在方法体中一定使用“return”关键字返回对应类型的结果,否则程序会
出现编译错误。
4)当需要在方法执行的时候为方法传递参数时才需要参数传递列表,如果不需要传递参数就可以省略,
不过小括号不可以省略,传递多个参数时以半角的逗号进行分隔(参数放小括号里)
如:第一个例子中output方法是无参的我只需要用来输出
school传递了一个学校,我需要他来告诉我小明的学校是什么。
5.1.3创建和使用对象
1.创建对象
类是一个事物的集合和抽象,代表这类事物共有的属性和行为,一个对象称为类的一个实例,是类一次实例化的结果,例如,“person1”是一个“人”类的具体对象(可以设为任意)
类的对象可以调用类中的成员,如属性和方法等
创建对象的语法格式:
类名 对象名 =new 类名()
1).new是关键字
2).左边的类名为对象的数据类型
3).右边的类名()称为类的构造方法(后面会学习)
结合第一个例子来理解
第一个例子中代码表示创建了Person类的一个对象,对象名是person1,Person是一个"人"类,而person1只是Person类的一个对象实例。
2.使用Java对象
在Java中,要引用对象的属性和方法,需要使用"."。(点)
使用Java对象的语法格式:
对象名.属性 //引用对象的属性
对象名.方法名() //引用对象的方法
创建对象后,用点可以看到所有的方法和属性
面向对象的优点如下几点:
1).与人类的思维习惯一致:面向对象的思维方式是从人类考虑问题的角度出发,把人类解决问题的思维过程转变为程序能够理解的过程、面向对象程序设计使用"类"来模拟现实世界中的抽象概念,用"对象"来模拟现实世界的实体从而用计算机解决现实问题
2)信息隐藏,提高了程序的可维护性和安全性:封装实现了模块化和信息隐藏,即将类的属性和行为封装在类中,这保证了对他们的修改不会影响到其他对象,利于维护。同时,封装使的在对象外部不能随意访问对象的属性和方法,避免了外部错误对它影响,提高了安全性
3)提高了程序的可重用性:一个类可以创建多个对象实例,体现了重用性。(创建多个对象是不能重名)
3.对象数组
需求:
定义包含3个元素的对象数组,数据类型为Person,并使用for循环遍历
5.2.1成员方法
类成员主要包含两部分:成员方法和成员变量(可以理解为属性)
1.带参数的方法
在实际应用中经常使用带参数或有返回值的方法
2.无参的方法
3.有返回值
public class Student {
public String name;
public void work(){
System.out.println("好好学习");
}
public void work(String why){
System.out.println(why+"好好学习");
}
public String works(){
return "能赚钱好好学习";
}
}
public class Text3 {
public static void main(String[] args) {
Student student=new Student();
student.name="小李";
student.work();
student.work("为了赚钱");
String works = student.works();
System.out.println(works);
}
}
结果:
好好学习
为了赚钱好好学习
能赚钱好好学习
有参就在多定义了一个变量,在你调用方法时可以控制
有返回值方法在调用是会把return的值返回过来.这里定义了一个works来接受
2.方法重载:
(1)方法重载的定义
方法重载是指一个类中定义多个同名的方法,但要求每个方法具有不同的参数类型或参数个数。
示例10:
需求:
定义一个不带参数的work()的方法,再定义一个带参数的work()方法,然后观察二者之间的区别
你调用work()时,括号不输入,则调用无参的方法,输入一个参调用一个参数的方法,
同理你如果定义了两个参数的方法,你调用work()时,在括号里输入两个参即可。
2)方法重载的特点:
1.在同一个类中
2.方法名相同
3.参数个数或类型不同
4.方法的返回值不能作为判断方法之间是否构成重载的依据
(3)方法重载的使用
方法重载定义后,通过对象调用时该如何选择?
(4)方法的重载的优点
方法重载其实是对原有的方法的一种升级,可以根据参数的不同,采用不同的实现方法,而且不需要编写多个名称,简化了类调用方法的代码
5.2.2成员变量
1.成员变量作用域
类中的属性,也就是直接在类中定义的变量称作成员变量,它定义在方法的外部。
在下面的代码中Student类中的name也不属于work()方法,而属于
Student类本身的属性,他们是Student类的成员变量
public class Student {
public String name;
public void work(){
String name="力王";
System.out.println("好好学习");
}
注意:
成员变量可以在声明时赋初始值。
分析:
work()方法中的变量name就是局部变量
注意:
虽然成员变量name和局部变量name的名称一样,但表示的却不是同一个变量,一般情况下,局部变量,在使用前需要赋值,否则会编译出错。局部变量在哪定义在哪使用
3.成员变量和局部变量的区别
使用成员变量和局部变量时需要注意如下几点:
(1).作用域不同。局部变量的作用域仅限于定义它的方法,在该方法外无法访问它。成员变量的作用域在整个类内部都是可见的,所有的成员方法都可以使用它,如果访问权限允许,还可以在类外部使用成员变量
(2).初始值不同,对于成员变量,如果在类定义中没有给它赋予初始值,Java会给它一个默认值,基本数据类型的值为0,引用类型的值为null,但是Java不会给局部变量赋予初始值,因此局部变量必须要定义并赋值后使用
(3)在同一个方法中,不允许有同名的局部变量。在不同的方法中,可以有同名的局部变量
(4)局部变量可以和成员变量名同名(可以使用this关键字来指代成员变量,下文介绍),并且一起使用,局部变量有更高的优先级
4.数据类型:
在Java中,变量的类型分为两种:一种是基本数据类型,一种是引用数据类型
Java中的引用数据类型包括3种:类、数组、接口
分析如下:
int为基本数据类型,当初始化num1并赋值后,将num1赋给num2,然后修改num2的值,运行后发现num1的值没有改变。
class为引用数据类型,当实例化person1对象并对其属性赋值后,将person1对象赋给person2对象,然后修改person2的值,运行后发现person1的属性值发生变化。
几乎同样的操作,为什么会有完全相反的结果?这是因为int和class在内存种的存储方式不同,这也是基本数据类型和引用数据类型的主要区别。
对于基本数据类型,不同的变量会分配不同的存储空间,并且存储空间中存储的是该变量的值,赋值操作传递的是变量的值,改变一个变量的值不会影响另外一个变量的值
对于引用数据类型,赋值是把原对象的引用(可以理解内存地址)传递给另外一个引用,对数组而言,当用一个数组名直接给另一个数组赋值时,相当于传递一个引用,此时,这两个引用指向同一个数组,也就是指向同一内存空间。
注意: String属于引用数据类型,但String创建对象初始化后(字符串是常量),不可改变,String类的任何改变,都是返回一个新的String类对象。地址不会改变。
6.2.3构造方法
Java中,当类创建一个对象时会自动调用该类的构造方法,构造方法分为默认构造方法和带参数的构造方法
1.构造方法的定义
构造方法的主要作用是进行一些数据的初始化
定义构造方法的语法格式如下。
【访问修饰符】 方法名(【参数列表】){
//省略方法体的代码
}
1).构造方法没有返回值
2).默认构造方法没有参数,因此参数列表可选
3).构造方法的方法名与类名相同
public class Student1 {
String name;
public void getname(){
System.out.println(name);
}
public Student1(){
this.name="小白";
}
}
public class Text4 {
public static void main(String[] args) {
Student1 student1=new Student1();
student1.getname();
}
}
结果为:小白
我没有给name,他的默认值从null变为了小白,这就是构造方法的用途:初始化。
注意:
如果自定义一个或多个构造方法,则Java不会自动添加默认构造方法
2.构造方法重载
构造方法也可以重载,即在同一个类中可以定义多个重载的构造方法。
分析:
在成员变量的示例中多次用到了this关键字,this的含义是什么呢?
this关键字是对一个对象的默认引用,每个实例方法内部都有一个this引用变量,指向调用这个方法的对象,其实就是指当前对象的引用,通俗点理解本对象自己
this使用举例如下:
this.属性名:
表示本对象自己的属性使用this调用成员变量,解决变量和局部变量的同名冲突
public class Student1 {
String name;
public void what(){
String name="小李";
System.out.println(this.name+"下课邀请"+name+"玩游戏");
}
}
ublic class Text5 {
public static void main(String[] args) {
Student1 student1=new Student1();
student1.name="小明";
student1.what();
}
}
结果:
小明下课邀请小李玩游戏
分析:
很明显this.name为类的name也就是成员变量。如果没有this关键字,则name优先指方法里的小李。
通过程序的运行结果我们可以看出,在创建对象的时候,对象的属性被赋予了正确初始值。这个程序本身非常的简单,谁都可以理解,但是大家请注意,我们在定义构造方法的时候,把表示姓名、年龄和身高的参数分别命名为:n、a和h,这种命名的可读性有点差,为了提高可读性,我们把构造方法的参数名称修改为name、age和height,用this区分即可
示例:
public Person(String name,int age,double height){
name=name;
age=age;
height=height;
}
结果:
我叫null,今年0岁
Process finished with exit code 0
null和0都是数据初始化的值
分析:
同名情况下,局部变量的优先级更高”原则
在构造方法执行的过程中,虚拟机会把参数值赋给”参数本身”,而不是赋值给对象的属性!
public Person(String name,int age,double height){
this.name=name;
this.age=age;
this.height=height;
}
修改成这样即可。
(2)this.方法名:
表示本对象自己的方法
我们给Person类增加了一个”打招呼”的方法叫做greet。在introduce方法当中,就可以通过”this.方法名”的方式来调用这个方法,表示调用的是”本对象自己的greet”方法。这是this关键字的第二种用法。当然,在introduce方法中并没有出现其他对象,所以方法名前面的this关键字也可以省略不写。
public class Student1 {
String name;
public void greet(){
System.out.println("hello,大家好");
}
public void introduce(){
this.greet();
System.out.println("我叫"+name);
}
}
public class Text5 {
public static void main(String[] args) {
Student1 student1=new Student1();
student1.name="小明";
student1.introduce();
}
}
结果:hello,大家好
我叫小明
(3)this关键字3
还有另外一种很重要的用法,那就是在this关键字的后面加上小括号,这样就表示调用了某个类自身的构造方法,为了讲解这种用法我们再来修改一下Person类:
我们给Person类又增加了一个构造方法。这个构造方法只有2个参数,并且只初始化2个属性。为了讲述方便,我们把上面的3个参数的构造方法称之为”构造方法①”,把下面的2个参数的构造方法称之为”构造方法②”。通过观察不难发现,这两个构造方法当中前2行代码是相互重复的,为了避免这种重复性的代码出现,我们可以在”构造方法①”当中调用”构造方法②”。调用的方式如下:
//构造方法1
public Person(String name,int age,double height){
this(name,age); //调用构造方法2
this.height=height;
}
//构造方法2
public Person(String name,int age){
this.name=name;
this.age=age;
}
在”构造方法①”中,通过”this(参数);”的方式调用了”构造方法②”。这就是this关键字的又一种用法。很多同学可能不理解,为什么要通过这种方式来调用构造方法呢?我们难道不能直接写一个”Person(name,age);”来调用吗?这里必须做出解释:在Java语言中,一个类的构造方法与类名相同。但是,一个类当中也可以定义一个与类名相同的”普通方法”,换句话说就是:并不是只有构造方法与类名相同,”普通方法”也可以取和类相同的名称(只不过全世界的程序员都不会这么干)。那么,在这种情况下,编译器如何区分这个方法是”普通方法”还是”构造方法”呢?很简单,”普通方法”的名称前面必须定义返回值类型,而”构造方法”的名称前面则没有返回值类型的定义。这样,编译器就能够分得清哪个是”构造方法”,哪个是”和类同名的普通方法”。
定义的时候分得清,但是在调用的时候,都是通过方法名来调用的,这时如何分得清代码中哪一句调用的是”构造方法”, 哪一句调用的是”和类同名的普通方法”呢?为了解决这个问题,Java语言规定,在本类中调用构造方法的时候,需要通过”this(参数)”的方式来调用。除此之外,Java语言还规定了这种调用方式所必须遵守的规则。首先,这种”this(参数)”的方式只能在”其他构造方法中”使用,不能在普通方法中用。如果在普通方法中按这种方式使用,将被视为语法错误,如下代码:
public void greet(){
this("张三",20);//此处代码错误,不能在普通方法中调用
System.out.println("hello,大家好");
}
注意:
构造方法①中调用了构造方法②,并没有出现new关键字,调用构造方法②仅仅是完成了name和age这两个属性的初始化,并不会创建出两个对象。
我们要思考的第二个问题是:既然Java语言允许”普通方法”的名称与类名相同,而构造方法也与类名相同,那么在Person以外的类当中如果写上了”Person(参数)”这样的代码,虚拟机如何判断所调用的是普通方法还是构造方法呢?答案也很简单,如果”Person(参数)”的前面出现了new关键字,这就说明调用的是构造方法,否则说明调用的是普通方法。
(4).外部类名.this.属性
this关键字在我们编写内部类代码的时候,还有一种用途,那就是区分属性或方法的具体归属
public class Outter { //定义一个外部类
int a;
class Intter{ //定义一个内部类
public void output(){
System.out.println(a);
}
}
public Outter(int a){ //给a给个初值
this.a=a;
}
}
public class Text7 {
public static void main(String[] args) {
Outter outter=new Outter(6);
Outter.Intter intter=outter.new Intter(); //实例一个内部类 intter
intter.output();
}
}
结果:6
分析:
在这段代码中,定义了外部类Outter,Outter有一个属性a,并且Outter中又定义了内部类,在内部类的printA()方法中调用了外部类的a属性。我们都知道,一个内部类可以直接访问它所在外部类的属性和方法。这个特性在我们的上面这段代码中得到了体现。但是,如果内部类中出现了与外部类同名的属性或方法时,该如何区分调用的到底是哪个属性或方法呢?比如说,在Inner类中也出现了a属性,那么输出语句中的a到底是指哪个a呢?很简单,如果输出语句中直接写a,那么调用的是内部类的a属性。为了强调它是内部类的a属性,我们也可以在a的前面加this关键字。如果我们希望调用的是外部类的a属性,可以用”外部类名.this.a”的方式来调用(this就近)
注意:
因为this是在对象内部指代自身的引用,所以this只能调用实例变量、实例方法和构造方法,不能调用类变量和类方法,也不能调用局部变量。
6.3.1封装概述
Java中封装的实质就是将类的状态信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法开实现对隐藏信息的操作和访问。
封装反映了事物的相对独立性,有效避免了外部错误对此对象的影响,并且能对对象使用者由于大意产生的错误操作起到预防作用。同样面向对象编程提倡对象之间实现松耦合关系。
封装的好处在于隐藏类的实现细节,让使用者只能通过程序员规定的方法来访问数据,可以方便的加入存取控制修饰符,来限制不合理的操作。
注意:
松耦合就是指尽量减少对象之间的关联性,以降低他们之间的复杂性和依赖性。
6.3.2封装的步骤
1.修改属性的可见性
将Person类中的属性public修改为private即可
public class Person{
private String name;
private String gender;
private String age;
}
分析:将public修改为private后,其他类就无法访问,如果访问则需要进行封装的第二部
2.设置setter和getter()方法
将Person类中的私有属性添加setter和getter()方法
public class Person{
private String name;
private String gender;
private int age;
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public String getGender(){
return gender;
}
pubic void setGender(String gender){
this.gender=gender;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age=age;
}
}
3.设置属性的存取限制
此时,还没对属性设置合法性检查,需要在setter方法中进一步利用条件判断语句进行赋值限制。
示例20:
为setter方法设置限制
public class Person {
public String name;
public int age;
public String gender;
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public String getGender(){
return gender;
}
public void setGender(String gender){
this.gender=gender;
}
public int getAge(){
return age;
}
//修改set方法,设置合法性检查
public void setAge(int age){
if (age<0||age>150) {
System.out.println("***输入年龄为"+age+",该年龄不合法,将重置***!");
return;
}
this.age=age;
}
//构造方法
public Person(){
this.name="无名氏";
this.gender="男";
this.age=18;
}
public Person(String name,String gender,int age){
this.name=name;
this.gender=gender;
this.age=age;
}
//方法:自我介绍方法:转义字符:\r表是把光标移到所在行开头;\n是把光标移到下一行开头
public void say(){
System.out.println("自我介绍以下\r\n姓名:"+this.name+"\r\n性别:"+this.gender+"\r\n年龄:"+this.age+"岁");
}
}
5.4.1包的概述
Java中的包机制也是封装的一种形式。
包的主要有以下方面的作用:
1).包允许将类组合成较小的单元(类似文件夹),易于找到和使用相应的类文件
2).防止命名冲突:Java中只有在不同包中的类才能重名。不同的程序员命名同名的类在所难免,类名就容易管理了,A定义了一个类Sort,封装在包A中,B定义了一个类Sort,封装在包B中,在使用时,为了区别A和B定义的Sort类,可以通过包名区分开,如A.Sort和B.Sort分别对应于A和B定义的Sort类。
5.4.2包的定义
定义包的语法格式如下:
package包名:
package是关键字
包的声明必须是Java源文件中的第一条非注释性语句,而且一个源文件只能有一个包声明语句,设计的
包需要与文件系统结构相对应。因此,在命名包时,要遵守以下编码规范。
1).一个唯一的包名前缀通常是全部小写的ASCII字母,并且是一个顶级域名com、edu、gov、net及org,通常使用组织的网络名的逆序。例如,如果域名为javagroup.net,可以声明包为“package net.javagroup.mypackage;”
2) 包名的后续部分依次不同机构各自内部的规范不同而不同。这类名规范可能以特定目录名的组成来区分部门、项目、机器或注册名、如“package net.javagroup.research.powerproject”。research表示项目名,
powerproject表示部门名
6.4.3包的使用
示例21:
使用包将Person类和PersonTest类进行分类
import cn.shujia.pack1.Person;
使用访问修饰符
6.5.1类和类成员的访问控制
包实际上是一种访问控制机制,通过包来限制和制约类之间的访问关系。访问修饰符也同样可以限制和制约类之间的访问关系。
1.Java中类的访问修饰符
作用域\修饰符 | 同一包中 | 非同一包中 |
---|---|---|
public | 可以使用 | 可以使用 |
默认修饰符(default) | 可以使用 | 不可以使用 |
2.类成员的访问修饰符
public:公有的
被声明为public的类、方法、构造方法和接口能够被任何其他类访问。
如果几个相互访问的public类分布在不用的包中,则需要导入相应public类所在的包。由于类的继承性,类所有的公有方法和变量都能被其子类继承。Java程序的main() 方法必须设置成公有的,否则,Java解释器将不能运行该类
调用一个包中所有的类可以用 .*
protected:受保护的
被声明为protected的变量、方法和构造方法能被同一个包中的任何其他类访问,也能够被不同包中的子类访问。
protected访问修饰符不能修饰类和接口,方法和成员变量能够声明为protected,但是接口的成员变量和成员方法不能声明为protected。
子类能访问protected修饰符声明的方法和变量,这样就能保护不相关的类使用这些方法和变量。
下面的父类使用了protected访问修饰符,子类重载了父类的bark()方法。
1 public class Dog{
2 protected void bark() {
3 System.out.println("汪汪,不要过来");
4 }
5 }
6 class Teddy extends Dog{ // 泰迪
7 void bark() {
8 System.out.println("汪汪,我好怕,不要跟着我");
9 }
10 }
如果把bark()方法声明为private,那么除了Dog之外的类将不能访问该方法。如果把bark()声明为public,那么所有的类都能够访问该方法。如果我们只想让该方法对其所在类的子类可见,则将该方法声明为protected。
private:私有的
私有访问修饰符是最严格的访问级别,所以被声明为private的方法、变量和构造方法只能被所属类访问,并且类和接口不能声明为private。
声明为私有访问类型的变量只能通过类中公共的Getter/Setter方法被外部类访问。
private访问修饰符的使用主要用来隐藏类的实现细节和保护类的数据。
public class Dog{
2 private String name;
3 private int age;
4 public String getName() {
5 return name;
6 }
7 public void setName(String name) {
8 this.name = name;
9 }
10 public int getAge() {
11 return age;
12 }
13 public void setAge(int age) {
14 this.age = age;
15 }
16 }
子中,Dog类中的name、age变量为私有变量,所以其他类不能直接得到和设置该变量的值。为了使其他类能够操作该变量,定义了两对public方法,getName()/setName() 和 getAge()/setAge(),它们用来获取和设置私有变量的值。
默认的:不使用任何关键字
不使用任何修饰符声明的属性和方法,对同一个包内的类是可见的。接口里的变量都隐式声明为public static final,而接口里的方法默认情况下访问权限为public。
如下例所示,类、变量和方法的定义没有使用任何修饰符
1 class Dog{
2 String name;
3 int age;
4
5 void bark(){ // 汪汪叫
6 System.out.println("汪汪,不要过来");
7 }
8 void hungry(){ // 饥饿
9 System.out.println("主人,我饿了");
10 }
11 }
如何使用访问控制符
访问控制符可以让我们很方便的控制代码的权限:
-
当需要让自己编写的类被所有的其他类访问时,就可以将类的访问控制符声明为 public。
-
当需要让自己的类只能被自己的包中的类访问时,就可以省略访问控制符。
-
当需要控制一个类中的成员数据时,可以将这个类中的成员数据访问控制符设置为 public、protected,或者省略。
-
作用域\修饰符 同一类中 同一包中 子孙类中 其他包 private 可以使用 不可以使用 不可以使用 不可以使用 默认修饰符 可以使用 可以使用 不可以使用 不可以使用 protected 可以使用 可以使用 不可以使用 不可以使用 public 可以使用 可以使用 可以使用 可以使用
示例23:
Person和 Test类在同一包中
public class Person{
private String name;
public int age;
protected String gender;
}
Test类中:
public void test1(){
Person person = new Person();
person.gender="111";
person.name="111";//非法,报错
}
6.5.2 static关键字
一个类可以创建n个对象。如果n个对象中的某些数据需要共用,就需要使用static关键字修饰这些数据。
Java中,一般情况下调用类的成员都需要先创建类的对象,然后同过对象进行调用。使用static关键字可以实现通过类名加"."直接调用类的成员,不需要创建类的对象。使用staic修饰的属性和方法属于类,不属于具体的某个对象。
1.用static关键字修饰属性
将Person类的name、gender和age属性保留,新建一个static修饰的属性,并调用。
分析如下:
使用static修饰的属性不依赖于任何对象,用类名直接加"."调用即可。
使用static修饰的属性不依赖于任何对象,用类名直接加“.”调用即可。
示例24:
public Person class{
public static int PERSON_LIVE;//人的生命只有一次
}
测试:
public void test1(){
Person.PERSON_LIVE=1;
}
在实际开发中,用static关键字修饰属性的最常用场景就是定义使用final关键字修饰的常量。使用final
关键字修饰的常量在整个程序运行时都不能被改变,和具体的对象没有关系,因此使用static修饰,例如“
static final int PERSON_LIVE”
注意:
1.常量名一般由大写字母组成
2.声明常量时一定要赋值初值
2.用static关键字修饰方法
用staic修饰的方法称为静态方法或者类方法,不用static关键字修饰的方法称为实例方法
实例25:
将Person中的showDetails()方法使用static关键字修饰,并调用
public class Person{
public static void showDetails(){
System.out.println("1111111111");
}
}
测试:
public static void main(String[] args) {
Person.showDetails();
}
注意:
静态方法只能访问静态成员,实例方法可以访问静态和实例成员。之所以不允许静态方法访问实例成员变量,是因为实例成员变量是属于某个对象的,而静态方法在执行时,并不一定存在对象。同样,因为实例方法可以访问实例成员变量,如果允许静态方法调用实例方法,将间接地允许它使用实例成员变量,所以它也不能调用实例方法。基于同样的道理,静态方法中也不能使用关键字this。
main()方法是一个典型的静态方法,它同样遵循一般静态方法的规则,所以它可以由系统在创建对象之前就调用
本章总结:
1.了解了类和对象,也学习了如何定义类,创建对象和使用对象
2.面向对象的优点:与人类的思维习惯一致,封装使信息隐藏,提高了程序的可维护性和安全性,一个类可以创建多个对象的实例,体现了重用性。
3.对象用来描述客观事物的一个实体,由一组属性和方法构成
4.类是具有相同的顺序和方法的一组对象的集合
5.使用类的步骤是,使用class定义类、使用new关键字创建类的对象,使用"."访问类的属性和方法。
6.如果一个类中包含了两个或两个以上方法,他们方法名相同,方法参数列表不同,则称为给重载。
7.构造方法用于创建类的对象。构造方法的作用主要就是创建对象时执行一些初始化操作。可以通过构造方法重载来实现多种初始化行为。
8.封装的好处在于隐藏类的实现细节,让使用者只能通过程序员规定的方法来访问数据库,可以方便的加入存取控制修饰符,以限制不合理操作。
9.Java中包含类的访问修饰符和类成员访问修饰符,其作用与不同。
10.static关键字修饰的属性和方法,不属于具体的对象,采用类名加"."方法即可直接访问。