第五章 面向对象基础 1、面向对象编程设计思想 1.1、编程语言概述 Java是一种计算机程序设计语言。所有的计算机程序一直都是围绕着两件事在进行的,程序设计就是用某种语言编写代码来完成这两件事,所以程序设计语言又称为编程语言(编写程序的语言)。
如何表示和存储数据
基本数据类型的常量和变量:表示和存储一个个独立的数据
对象:表示和存储与某个具体事物相关的多个数据(例如:某个学生的姓名、年龄、联系方式等)
数据结构:表示和存储一组对象,数据结构有数组、链表、栈、队列、散列表、二叉树、堆……
基于这些数据都有什么操作行为,其实就是实现什么功能
数据的输入和输出
基于一个或两个数据的操作:赋值运算、算术运算、比较运算、逻辑运算等
基于一组数据的操作:统计分析、查找最大值、查找元素、排序、遍历等
1.2、程序设计方法 C语言是一种面向过程的程序设计语言,因为C语言是在面向过程思想的指引下去设计、开发计算机程序的。
Java语言是一种面向对象的程序设计语言,因为Java语言是在面向对象思想的指引下去设计、开发计算机程序的。
其中面向对象和面向过程都是一种编程思想,基于不同的思想会产生不同的程序设计方法。
面向过程的程序设计思想(Process-Oriented Programming),简称POP
面向对象的程序设计思想( Object Oriented Programming),简称 OOP
关注的焦点是类:面向对象思想就是在计算机程序设计过程中,参照现实中事物,将事物的属性特征、行为特征抽象出来,用类来表示。某个事物的一个具体个体称为实例或对象。
代码结构:以类为组织单位。每种事物都具备自己的属性 (即表示和存储数据,在类中用成员变量表示)和行为/功能 (即操作数据,在类中用成员方法表示)。
2、类与对象 类和对象是面向对象编程的两个主要方面。Java 中的一切都与类、对象及其属性和方法相关联。例如:在现实生活中,汽车是一个物体。汽车有属性,比如重量和颜色,也有方法,比如行驶和刹车。
类就像一个构造对象的模具,或者创建对象的“蓝图”。
类
对象
车
宝马、奔驰、比亚迪、保时捷
水果
苹果、香蕉、哈密瓜、芒果
手机
iPhone、华为、小米、VIVO
2.1、如何创建类 关键字:class(小写)
类的定义格式举例:
1 2 3 public class Student { }
2.2、对象的创建 关键字:new
1 2 3 4 5 6 7 8 new 类名()类名 对象名 = new 类名(); Student student1 = new Student ();Student student2 = new Student ();
3、类属性(成员变量) 3.1 声明类成员变量 类属性是类中的变量。类属性的另一个术语是字段 。下面创建类一个 “人” 类,并为它添加了三个属性,名字、性别和年龄。
1 2 3 4 5 public class Person { String name; char gender; int age; }
3.2 对象的实例变量 实例变量的特点 (1)实例变量的值是属于某个对象的
必须通过对象才能访问实例变量
每个对象的实例变量的值是独立的
(2)实例变量有默认值
分类
数据类型
默认值
基本类型
整数(byte,short,int,long)
0
浮点数(float,double)
0.0
字符(char)
‘\u0000’
布尔(boolean)
false
数据类型
默认值
引用类型
数组,类,接口
null
实例变量的访问 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class TestPerson { public static void main (String[] args) { Person p1 = new Person (); p1.name = "张三" ; p1.age = 23 ; p1.gender = '男' ; Person p2 = new Person (); System.out.println("p1对象的实例变量:" ); System.out.println("p1.name = " + p1.name); System.out.println("p1.age = " + p1.age); System.out.println("p1.gender = " + p1.gender); System.out.println("p2对象的实例变量:" ); System.out.println("p2.name = " + p2.name); System.out.println("p2.age = " + p2.age); System.out.println("p2.gender = " + p2.gender); } }
4、 方法(Method) 4.1 方法的概念 方法也叫函数,是一组代码语句的封装,从而实现代码重用,从而减少冗余代码,通常它是一个独立功能的定义,方法是一个类中最基本的功能单元。
1 2 3 4 5 6 Math.random()的random()方法 Math.sqrt(x)的sqrt(x)方法 System.out.println(x)的println(x)方法 Scanner input = new Scanner (System.in);input.nextInt()的nextInt()方法
4.2 方法的特点 (1)必须先声明后使用
类,变量,方法等都要先声明后使用
(2)不调用不执行,调用一次执行一次。
4.3 如何声明方法 声明方法的位置 声明方法的位置==必须在类中方法外==,即不能在一个方法中直接定义另一个方法。
声明位置示例:
1 2 3 4 5 6 7 8 类{ 方法1 (){ } 方法2 (){ } }
错误示例:
1 2 3 4 5 6 7 类{ 方法1 (){ 方法2 (){ } } }
声明方法的语法格式 1 2 3 【修饰符】 返回值类型 方法名(【形参列表 】)【throws 异常列表】{ 方法体的功能代码 }
(1)一个完整的方法 = 方法头 + 方法体。
方法头就是 【修饰符】 返回值类型 方法名(【形参列表 】)【throws 异常列表】,也称为方法签名,通常调用方法时只需要关注方法头就可以,从方法头可以看出这个方法的功能和调用格式。
方法体就是方法被调用后要指定的代码,也是完成方法功能的具体实现代码,对于调用者来说,不了解方法体如何实现的,并影响方法的使用。
(2)方法头可能包含5个部分,但是有些部分是可能缺省的
修饰符:可选的。方法的修饰符也有很多,例如:public、protected、private、static、abstract、native、final、synchronized等,后面会一一学习。其中根据是否有static,可以将方法分为静态方法和非静态方法。其中静态方法又称为类方法,非静态方法又称为实例方法。==接下来咱们先学习实例方法==。
返回值类型: 表示方法运行的结果的数据类型,方法执行后将结果返回到调用者
基本数据类型
引用数据类型
无返回值类型:void
方法名:给方法起一个名字,见名知意,能准确代表该方法功能的名字
参数列表:表示完成方法体功能时需要外部提供的数据列表
(3)方法体:方法体必须有{}括起来,在{}中编写完成方法功能的代码
关于方法体中return语句的说明:
return语句的作用是结束方法的执行,并将方法的结果返回去
如果返回值类型不是void,方法体中必须保证一定有 return 返回值; 语句,并且要求该返回值结果的类型与声明的返回值类型一致或兼容。
如果返回值类型为void时,方法体中可以没有return语句,如果要用return语句提前结束方法的执行,那么return后面不能跟返回值,直接写return ; 就可以。
return语句后面就不能再写其他代码了,否则会报错:Unreachable code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 public class MethodDefineDemo { void sayHello () { System.out.println("hello" ); } void printRectangle (int length, int width, char sign) { for (int i = 1 ; i <= length ; i++) { for (int j=1 ; j <= width; j++){ System.out.print(sign); } System.out.println(); } } int getIntBetweenOneToHundred () { return (int )(Math.random()*100 +1 ); } int max (int a, int b) { return a > b ? a : b; } }
4.4 如何调用实例方法 方法调用语法格式
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public class MethodInvokeDemo { public static void main (String[] args) { MethodDefineDemo md = new MethodDefineDemo (); System.out.println("-----------------------方法调用演示-------------------------" ); md.sayHello(); md.sayHello(); md.sayHello(); System.out.println("------------------------------------------------" ); md.printRectangle(5 ,10 ,'@' ); System.out.println("------------------------------------------------" ); md.getIntBetweenOneToHundred(); int num = md.getIntBetweenOneToHundred(); System.out.println("num = " + num); System.out.println(md.getIntBetweenOneToHundred()); System.out.println("------------------------------------------------" ); md.max(3 ,6 ); int bigger = md.max(5 ,6 ); System.out.println("bigger = " + bigger); System.out.println("8,3中较大者是:" + md.max(8 ,9 )); } }
回忆之前的代码:
1 2 3 4 5 6 7 8 Scanner input = new Scanner (System.in);System.out.print("请输入一个整数:" ); int num = input.nextInt();
形参和实参
形参(formal parameter):在定义方法时方法名后面括号中声明的变量称为形式参数(简称形参)即形参出现在方法定义时。
实参(actual parameter):调用方法时方法名后面括号中的使用的值/变量/表达式称为实际参数(简称实参)即实参出现在方法调用时。
调用时,实参的个数、类型、顺序顺序要与形参列表一一对应。如果方法没有形参,就不需要也不能传实参。
无论是否有参数,声明方法和调用方法是==()都不能丢失==
返回值问题 方法调用表达式是一个特殊的表达式:
如果被调用方法的返回值类型是void,调用时不需要也不能接收和处理(打印或参与计算)返回值结果,即方法调用表达式==只能==直接加;成为一个独立语句。
如果被调用方法有返回值,即返回值类型不是void,
方法调用表达式的结果可以作为赋值表达式的值,
方法调用表达式的结果可以作为计算表达式的一个操作数,
方法调用表达式的结果可以作为另一次方法调用的实参,
方法调用表达式的结果可以不接收和处理,方法调用表达式直接加;成为一个独立的语句,这种情况,返回值丢失。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class MethodReturnValue { public static void main (String[] args) { MethodDefineDemo md = new MethodDefineDemo (); md.sayHello(); md.printRectangle(5 ,10 ,'@' ); int bigger = md.max(7 ,3 ); System.out.println("bigger = " + bigger); int sum = md.getIntBetweenOneToHundred() + md.getIntBetweenOneToHundred(); System.out.println("sum = " + sum); int x = 4 ; int y = 5 ; int z = 2 ; int biggest = md.max(md.max(x,y),z); System.out.println("biggest = " + biggest); md.getIntBetweenOneToHundred(); } }
4.5 实例方法使用当前对象的成员 在实例方法中还可以使用当前对象的其他成员。在Java中当前对象用this表示。
this:在实例方法中,表示调用该方法的对象
如果没有歧义,完全可以省略this。
使用this. 案例:矩形类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class Rectangle { int length; int width; int area () { return this .length * this .width; } int perimeter () { return 2 * (this .length + this .width); } void print (char sign) { for (int i = 1 ; i <= this .width; i++) { for (int j = 1 ; j <= this .length; j++) { System.out.print(sign); } System.out.println(); } } String getInfo () { return "长:" + this .length + ",宽:" + this .width +",面积:" + this .area() +",周长:" + this .perimeter(); } }
可省略 this 的情况 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class Rectangle { int length; int width; int area () { return length * width; } int perimeter () { return 2 * (length + width); } void print (char sign) { for (int i = 1 ; i <= width; i++) { for (int j = 1 ; j <= length; j++) { System.out.print(sign); } System.out.println(); } } String getInfo () { return "长:" + length + ",宽:" + width +",面积:" + area() +",周长:" + perimeter(); } }
4.6 实例变量与局部变量的区别 1、声明位置和方式 (1)实例变量:在类中方法外 (2)局部变量:在方法体{}中或方法的形参列表、代码块中
2、在内存中存储的位置不同 (1)实例变量:堆 (2)局部变量:栈
3、生命周期
实例变量:和对象的生命周期一样,随着对象的创建而存在,随着对象被GC回收而消亡,而且每一个对象的实例变量是独立的。
局部变量:和方法调用的生命周期一样,每一次方法被调用而在存在,随着方法执行的结束而消亡,而且每一次方法调用都是独立。
4、作用域
实例变量:通过对象就可以使用,本类中“this.,没有歧义还可以省略this.”,其他类中“对象.”
局部变量:出了作用域就不能使用
5、修饰符(后面来讲)
实例变量:public,protected,private,final,volatile,transient等
局部变量:final
6、默认值
实例变量:有默认值
局部变量:没有,必须手动初始化。其中的形参比较特殊,靠实参给它初始化。
5、参数问题 5.1 特殊参数之一:可变参数 在JDK1.5 之后,当定义一个方法时,形参的类型可以确定,但是形参的个数不确定,那么可以考虑使用可变参数。可变参数的格式:
1 【修饰符】 返回值类型 方法名(【非可变参数部分的形参列表,】参数类型... 形参名){ }
可变参数的特点和要求:
(1)一个方法最多只能有一个可变参数
(2)如果一个方法包含可变参数,那么可变参数必须是形参列表的最后一个
(3)在声明它的方法中,可变参数当成数组使用
(4)其实这个书写“≈”
1 【修饰符】 返回值类型 方法名(【非可变参数部分的形参列表,】参数类型[] 形参名){ }
只是后面这种定义,在调用时必须传递数组,而前者更灵活,既可以传递数组,又可以直接传递数组的元素,这样更灵活了。
方法只有可变参数 案例:求n个整数的和
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class NumberTools { int total (int [] nums) { int he = 0 ; for (int i = 0 ; i < nums.length; i++) { he += nums[i]; } return he; } int sum (int ... nums) { int he = 0 ; for (int i = 0 ; i < nums.length; i++) { he += nums[i]; } return he; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class TestVarParam { public static void main (String[] args) { NumberTools tools = new NumberTools (); System.out.println(tools.sum()); System.out.println(tools.sum(5 )); System.out.println(tools.sum(5 ,6 ,2 ,4 )); System.out.println(tools.sum(new int []{5 ,6 ,2 ,4 })); System.out.println("------------------------------------" ); System.out.println(tools.total(new int []{})); System.out.println(tools.total(new int []{5 })); System.out.println(tools.total(new int []{5 ,6 ,2 ,4 })); } }
方法包含非可变参数和可变参数
非可变参数部分必须传入对应类型和个数的实参;
可变参数部分按照可变参数的规则传入0~n个对应类型的实参或传入1个对应类型的数组实参;
案例:
n个字符串进行拼接,每一个字符串之间使用某字符进行分割,如果没有传入字符串,那么返回空字符串””
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class StringTools { String concat (char seperator, String... args) { String str = "" ; for (int i = 0 ; i < args.length; i++) { if (i==0 ){ str += args[i]; }else { str += seperator + args[i]; } } return str; } }
1 2 3 4 5 6 7 8 9 10 11 public class StringToolsTest { public static void main (String[] args) { StringTools tools = new StringTools (); System.out.println(tools.concat('-' )); System.out.println(tools.concat('-' ,"hello" )); System.out.println(tools.concat('-' ,"hello" ,"world" )); System.out.println(tools.concat('-' ,"hello" ,"world" ,"java" )); } }
5.2 方法的参数传递机制 方法的参数传递机制:实参给形参赋值,那么反过来形参会影响实参吗?
方法的形参是基本数据类型时,形参值的改变不会影响实参;
方法的形参是引用数据类型时,形参地址值的改变不会影响实参,但是形参地址值里面的数据的改变会影响实参,例如,修改数组元素的值,或修改对象的属性值。
注意:String、Integer等特殊类型容易错
形参是基本数据类型 案例:编写方法,交换两个整型变量的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class PrimitiveTypeParam { void swap (int a, int b) { int temp = a; a = b; b = temp; } public static void main (String[] args) { PrimitiveTypeParam tools = new PrimitiveTypeParam (); int x = 1 ; int y = 2 ; System.out.println("交换之前:x = " + x +",y = " + y); tools.swap(x,y); System.out.println("交换之后:x = " + x +",y = " + y); } }
形参是引用数据类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class ReferenceTypeParam { void swap (MyData my) { int temp = my.x; my.x = my.y; my.y = temp; } public static void main (String[] args) { ReferenceTypeParam tools = new ReferenceTypeParam (); MyData data = new MyData (); data.x = 1 ; data.y = 2 ; System.out.println("交换之前:x = " + data.x +",y = " + data.y); tools.swap(data); System.out.println("交换之后:x = " + data.x +",y = " + data.y); } }
1 2 3 4 public class MyData { int x; int y; }
3、形参是数组 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public class ArrayTypeParam { void sort (int [] arr) { for (int i = 1 ; i < arr.length; i++) { for (int j = 0 ; j < arr.length - i; j++) { if (arr[j] > arr[j+1 ]){ int temp = arr[j]; arr[j] = arr[j+1 ]; arr[j+1 ] = temp; } } } } void iterate (int [] arr) { for (int i = 0 ; i < arr.length; i++) { System.out.print(arr[i]+" " ); } System.out.println(); } public static void main (String[] args) { ArrayTypeParam tools = new ArrayTypeParam (); int [] nums = {4 ,3 ,1 ,6 ,7 }; System.out.println("排序之前:" ); tools.iterate(nums); tools.sort(nums); System.out.println("排序之后:" ); tools.iterate(nums); } }
4、形参指向新对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class AssignNewObjectToFormalParam { void swap (MyData my) { my = new MyData (); int temp = my.x; my.x = my.y; my.y = temp; } public static void main (String[] args) { AssignNewObjectToFormalParam tools = new AssignNewObjectToFormalParam (); MyData data = new MyData (); data.x = 1 ; data.y = 2 ; System.out.println("交换之前:x = " + data.x +",y = " + data.y); tools.swap(data); System.out.println("交换之后:x = " + data.x +",y = " + data.y); } }
6、方法的重载
方法重载 :指在同一个类中,允许存在一个以上的同名方法,只要它们的参数列表不同即可,与修饰符和返回值类型无关。
参数列表:数据类型个数不同,数据类型不同(按理来说数据类型顺序不同也可以,但是很少见,也不推荐,逻辑上容易有歧义)。
重载方法调用:JVM通过方法的参数列表,调用匹配的方法。
先找个数、类型最匹配的
再找个数和类型可以兼容的,如果同时多个方法可以兼容将会报错
案例,用重载实现:
(1)定义方法求两个整数的最大值
(2)定义方法求三个整数的最大值
(3)定义方法求两个小数的最大值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class MathTools { public int max (int a,int b) { return a>b?a:b; } public double max (double a, double b) { return a>b?a:b; } public int max (int a, int b, int c) { return max(max(a,b),c); } }
7、对象数组 数组是用来存储一组数据的容器,一组基本数据类型的数据可以用数组装,那么一组对象也可以使用数组来装。
即数组的元素可以是基本数据类型,也可以是引用数据类型。当元素是引用数据类型是,我们称为对象数组。
注意:对象数组,首先要创建数组对象本身,即确定数组的长度,然后再创建每一个元素对象,如果不创建,数组的元素的默认值就是null,所以很容易出现空指针异常NullPointerException。
7.1 对象数组的声明和使用 案例:
(1)定义矩形类,包含长、宽属性,area()求面积方法,perimeter()求周长方法,String getInfo()返回圆对象的详细信息的方法
(2)在测试类中创建长度为5的Rectangle[]数组,用来装3个矩形对象,并给3个矩形对象的长分别赋值为10,20,30,宽分别赋值为5,15,25,遍历输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class Rectangle { double length; double width; double area () { return length * width; } double perimeter () { return 2 * (length + width); } String getInfo () { return "长:" + length + ",宽:" + width + ",面积:" + area() + ",周长:" + perimeter(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class ObjectArrayTest { public static void main (String[] args) { Rectangle[] array = new Rectangle [3 ]; for (int i = 0 ; i < array.length; i++) { array[i] = new Rectangle (); array[i].length = (i+1 ) * 10 ; array[i].width = (2 *i+1 ) * 5 ; System.out.println(array[i].getInfo()); } } }
8、构造器 我们发现我们new完对象时,所有成员变量都是默认值,如果我们需要赋别的值,需要挨个为它们再赋值,太麻烦了。我们能不能在new对象时,直接为当前对象的某个或所有成员变量直接赋值呢。
可以,Java给我们提供了构造器(Constructor)。
1、构造器的作用 new对象,并在new对象的时候为实例变量赋值。
2、构造器的语法格式 构造器又称为构造方法,那是因为它长的很像方法。但是和方法还是有所区别的。
1 2 3 4 5 6 7 8 【修饰符】 class 类名{ 【修饰符】 构造器名(){ } 【修饰符】 构造器名(参数列表){ } }
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class Student { private String name; private int age; public Student () {} public Student (String name,int age) { this .name = name; this .age = age; } public String getName () { return name; } public void setName (String name) { this .name = name; } public int getAge () { return age; } public void setAge (int age) { this .age = age; } public String getInfo () { return "姓名:" + name +",年龄:" + age; } }
注意事项:
构造器名必须与它所在的类名必须相同。
它没有返回值,所以不需要返回值类型,甚至不需要void
如果你不提供构造器,系统会给出无参数构造器,并且该构造器的修饰符默认与类的修饰符相同
如果你提供了构造器,系统将不再提供无参数构造器,除非你自己定义。
构造器是可以重载的,既可以定义参数,也可以不定义参数。
构造器的修饰符只能是权限修饰符,不能被其他任何修饰
1 2 3 4 5 6 7 8 9 10 11 12 13 public class TestStudent { public static void main (String[] args) { Student s1 = new Student (); Student s2 = new Student ("张三" ,23 ); System.out.println(s1.getInfo()); System.out.println(s2.getInfo()); } }
3、同一个类中的构造器互相调用
this():调用本类的无参构造
this(实参列表):调用本类的有参构造
this()和this(实参列表)只能出现在构造器首行
不能出现递归调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public class Student { private String name; private int age; public Student () { } public Student (String name,int age) { this (); this .name = name; this .age = age; } public String getName () { return name; } public void setName (String name) { this .name = name; } public int getAge () { return age; } public void setAge (int age) { this .age = age; } public String getInfo () { return "姓名:" + name +",年龄:" + age; } }
9、静态 9.1 静态关键字(static) 在类中声明的实例变量,其值是每一个对象独立的。但是有些成员变量的值不需要或不能每一个对象单独存储一份,即有些成员变量和当前类的对象无关。
在类中声明的实例方法,在类的外面必须要先创建对象,才能调用。但是有些方法的调用和当前类的对象无关,那么创建对象就有点麻烦了。
此时,就需要将和当前类的对象无关的成员变量、成员方法声明为静态的(static)。
9.2 静态变量 1、语法格式 有static修饰的成员变量就是静态变量。
1 2 3 【修饰符】 class 类{ 【其他修饰符】 static 数据类型 静态变量名; }
2、静态变量的特点
静态变量的默认值规则和实例变量一样。
静态变量值是所有对象共享。
静态变量的值存储在方法区。
静态变量在本类中,可以在任意方法、代码块、构造器中直接使用。
如果权限修饰符允许,在其他类中可以通过“类名.静态变量”直接访问,也可以通过“对象.静态变量”的方式访问(但是更推荐使用类名.静态变量的方式)。
静态变量的get/set方法也静态的,当局部变量与静态变量重名时,使用“类名.静态变量”进行区分。
分类
数据类型
默认值
基本类型
整数(byte,short,int,long)
0
浮点数(float,double)
0.0
字符(char)
‘\u0000’
布尔(boolean)
false
数据类型
默认值
引用类型
数组,类,接口
null
演示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 public class Employee { private static int total; static String company; private int id; private String name; { total++; id = total; } public Employee () { } public Employee (String name) { this .name = name; } public void setId (int id) { this .id = id; } public int getId () { return id; } public String getName () { return name; } public void setName (String name) { this .name = name; } public static int getTotal () { return total; } public static void setTotal (int total) { Employee.total = total; } @Override public String toString () { return "Employee{company = " + company + ",id = " + id + " ,name=" + name +"}" ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class TestStaticVariable { public static void main (String[] args) { System.out.println("Employee.total = " + Employee.getTotal()); Employee c1 = new Employee ("张三" ); Employee c2 = new Employee (); System.out.println(c1); System.out.println(c2); System.out.println("Employee.total = " + Employee.getTotal()); Employee.company = "尚硅谷" ; System.out.println(c1); System.out.println(c2); c1.company = "超级尚硅谷" ; System.out.println(c1); System.out.println(c2); } }
3、静态类变量和非静态实例变量、局部变量
静态类变量(简称静态变量):存储在方法区,有默认值,所有对象共享,生命周期和类相同,还可以有权限修饰符、final等其他修饰符
非静态实例变量(简称实例变量):存储在堆中,有默认值,每一个对象独立,生命周期每一个对象也独立,还可以有权限修饰符、final等其他修饰符
局部变量:存储在栈中,没有默认值,每一次方法调用都是独立的,有作用域,只能有final修饰,没有其他修饰符
9.3 静态方法 1、语法格式 有static修饰的成员方法就是静态方法。
1 2 3 4 5 【修饰符】 class 类{ 【其他修饰符】 static 返回值类型 方法名(形参列表){ 方法体 } }
2、静态方法的特点
静态方法在本类的任意方法、代码块、构造器中都可以直接被调用。
只要权限修饰符允许,静态方法在其他类中可以通过“类名.静态方法“的方式调用。也可以通过”对象.静态方法“的方式调用(但是更推荐使用类名.静态方法的方式)。
静态方法可以被子类继承,但不能被子类重写。
静态方法的调用都只看编译时类型。
1 2 3 4 5 6 7 8 9 10 public class Father { public static void method () { System.out.println("Father.method" ); } public static void fun () { System.out.println("Father.fun" ); } }
1 2 3 4 5 6 7 public class Son extends Father { public static void fun () { System.out.println("Son.fun" ); } }
1 2 3 4 5 6 7 8 9 10 public class TestStaticMethod { public static void main (String[] args) { Father.method(); Son.method(); Father f = new Son (); f.method(); } }
9.4 静态和非静态的区别 1、本类中的访问限制区别 静态的类变量和静态的方法可以在本类的任意方法、代码块、构造器中直接访问。
非静态的实例变量和非静态的方法==只能==在本类的非静态的方法、非静态代码块、构造器中直接访问。
即:
静态直接访问静态,可以
非静态直接访问非静态,可以
非静态直接访问静态,可以
静态直接访问非静态,不可以
2、在其他类的访问方式区别 静态的类变量和静态的方法可以通过“类名.”的方式直接访问;也可以通过“对象.”的方式访问。(但是更推荐使用==”类名.”==的方式)
非静态的实例变量和非静态的方法==只能==通过“对象.”方式访问。
3、this和super的使用 静态的方法和静态的代码块中,==不允许==出现this和super关键字,如果有重名问题,使用“类名.”进行区别。
非静态的方法和非静态的代码块中,可以使用this和super关键字。
9.5 静态导入 如果大量使用另一个类的静态成员,可以使用静态导入,简化代码。
1 2 import static 包.类名.静态成员名;import static 包.类名.*;
演示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import static java.lang.Math.*;public class TestStaticImport { public static void main (String[] args) { System.out.println(Math.PI); System.out.println(Math.sqrt(9 )); System.out.println(Math.random()); System.out.println("----------------------------" ); System.out.println(PI); System.out.println(sqrt(9 )); System.out.println(random()); } }