面向对象(上)
一、面向过程与面向对象
(一)面向过程思想概述
面向过程就是分析出解决问题所需要的步骤,然后用方法把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。
而具体的每一步都需要我们去实现和操作。这些步骤相互调用和协作,完成我们的需求。在上面的每一个具体步骤中我们都是参与者,并且需要面对具体的每一个步骤和过程,这就是面向过程最直接的体现。
那么什么是面向过程开发呢? 面向过程开发,其实就是面向着具体的每一个步骤和过程,把每一个步骤和过程完成,然后由这些功能方法相互调用,完成需求。
面向过程的代表语言:C语言
(二)面向对象思想概述
当需求单一,或者简单时,我们一步一步去操作没问题。可随着需求的更改,功能的增多,发现需要面对每一个步骤很麻烦了。这时就我们开始思索,能不能把这些步骤和功能再进行封装,封装时根据不同的功能,进行不同的封装,功能类似的封装在一起。这样结构就清晰了很多。用的时候,找到对应的类就可以了。
面向对象就是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
那么什么是面向对象开发呢?面向对象开发就是不断地创建对象,使用对象,指挥对象做事情,从而完成需求。
(三)面向对象思想特点
(1)是一种更符合我们思想习惯的思想
(2)可以将复杂的事情简单化
(3)将我们从执行者变成了指挥者,角色发生了转换
(四)面向对象思想在生活中的例子
在生活中,面向过程的思想就好比手洗衣服,首先需要接盆水,然后把衣服放进去,再倒上洗衣液,然后用手揉搓衣服,再漂净衣服,最后晾干。这其中的每一步都需要我们一步步实现,每一步我们都是参与者。
而面向对象,则是我们可以买一台全自动洗衣机,只需要按下按键即可完成洗衣服(调用类中方法)。
(五)面向对象的特征
1.封装
封装性是面向对象编程的核心思想
指的就是将描述某种实体的数据和基于这些数的操作集合到一起,形成一个封装体
封装的思想保证了类内部数据结构的完整性,使用户无法轻易直接操作类的内部数据,这样降低了对内部数据的影响,提高了程序的安全性和可维护性。
2.继承
继承是Java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或类从父类继承方法,使得子类具有父类相同的行为。
3.多态
多态指同一个实体同时具有多种形式。它是面向对象程序设计(OOP)的一个重要特征。
接口的多种不同的实现方式即为多态。
二、类与对象概述
-
这个现实世界是由事物组成。生活中我们如何描述现实世界事物?
举例: 描述学生
属性:姓名 , 年龄 , 性别 …
行为:学习 , 吃饭 , 睡觉 … -
属性: 就是该事物的描述信息
行为: 就是该事物能够做什么编程语言,就是为了模拟现实中的事物,我们学习的Java语言最基本单位是类,所以,我们就应该把事物用一个类来体现。
-
由此我们就得到了现实中的事物和类的对应关系
事物 ----------------- 类
属性 ----------------- 成员变量
行为 ----------------- 成员方法 -
定义类其实就是定义类的成员(成员变量和成员方法)
(1)成员变量 和以前定义变量是一样的,只不过位置发生了改变。在类中,方法外。
(2)成员方法 和以前定义方法是一样的,只不过把static去掉,后面在详细讲解static的作用。 -
类和对象的概念
(1)类:是一组相关的属性和行为的集合
(2)对象:是该类事物的具体体现
(3)举例:
类——学生
对象——班长
三、类与对象应用
1.学生类
定义一个学生类
public class Student {
//属性——————成员变量
//成员变量要定义在类中方法外
String name;//可以给属性赋初值,不赋值的情况下为该数据类型的默认值,此处为null
int age;//默认值0
char sex;//默认值空字符
//行为——————成员方法
public void study(){
System.out.println("正在学习中...");
}
public void eat(){
System.out.println("正在吃饭中...");
}
public void sleep(){
System.out.println("正在睡觉中...");
}
}
同一个包下,定义一个测试类创建对象并调用类属性和功能
public class MyTest {
public static void main(String[] args) {
//定义一个类,体现的就是封装的思想---封装了成员变量和成员方法
//定义一个类使用关键字 class
//我要定义一个学生类
//类是一个抽象的概念,你无法直接使用他的属性和功能,我们要使用该类,那必须要对类进行实例化
//所谓实例化,就是创建该类的对象。如何创建一个类的对象呢?使用关键字new
//创建该类的实例(对象)
Student st = new Student();
//设置属性的值
st.name="张三";
st.age=18;
st.sex='男';
//有了对象以后,通过对象调用类中的属性和功能
//获取属性 对象名.属性名
String name=st.name;
int age=st.age;
char sex=st.sex;
System.out.println(name);
System.out.println(age);
System.out.println(sex);
//调用方法 对象名.方法名()
st.eat();
st.sleep();
st.study();
System.out.println("------------------------------------");
//一个类可以创建很多对象
Student st2 = new Student();
st2.name="小红";
st2.age=19;
st2.sex='女';
System.out.println(st2.name);
System.out.println(st2.age);
System.out.println(st2.sex);
st2.eat();
st2.sleep();
st2.study();
}
}
2.老师类
定义一个老师类
public class Teacher {
String name;
int age;
public void teach(){
System.out.println("正在教课中...");
}
public void sleep(){
System.out.println("正在休息中...");
}
}
同一个包下,定义一个测试类创建对象并调用类属性和功能
public class MyTest {
public static void main(String[] args) {
Teacher t1 = new Teacher();
t1.name = "张三";
t1.age = 26;
System.out.println(t1.name);
System.out.println(t1.age);
Teacher t2 = new Teacher();
t2.name = "赵四";
t2.age = 27;
Teacher t3=t1;
t3.name="田七";
t1.age=30;
System.out.println(t1.name);
System.out.println(t1.age);
System.out.println(t2.name);
System.out.println(t2.age);
System.out.println(t3.name);
System.out.println(t3.age);
}
}
内存解析
首先.class文件被加载进方法区,main方法被调用进栈,执行到第一句代码时,堆内存为t1对象开辟空间,并赋了默认值,再将空间的地址赋给t1这个引用,因此t1便指向了该空间。执行到第二、三句代码,便通过t1找到空间,将name改为“张三”,age改为26,此时的输出就为“张三”和26。再执行下面的代码,堆内存为t2对象开辟空间并初始化默认值,再将空间的地址赋给t2这个引用,接着再将name改为“赵四”,age改为27。然后,将t1这个引用赋给t3,t3并没有new,所以没有开辟新的空间,而是指向了t1指向的空间,因此t1和t3共同操作一个空间。最后将t3.name改为“田七”,也即改变了t1.name,又将t1.age改为30,于是后面的输出便为“田七”,30,“赵四”,27,“田七”,30。
四、成员变量和局部变量的区别
- 在类中的位置不同
成员变量:在类中方法外
局部变量:在方法定义中或者方法声明上(形参) - 在内存中的位置不同
成员变量:在堆内存
局部变量:在栈内存 - 生命周期不同
成员变量:随着对象的创建而存在,随着对象的消失而消失
局部变量:随着方法的调用而存在,随着方法的调用完毕而消失 - 初始化值不同
成员变量:有默认初始化值
局部变量:没有默认初始化值,必须定义,赋值,然后才能使用。
注意事项:局部变量名称可以和成员变量名称一样,在方法中使用的时候,采用的是就近原则。
变量的访问原则——就近原则:方法中要访问一个变量,会先在局部位置找,找到就使用;如果找不到,会找成员变量,找到就使用 。
案例演示
1.
/*
一个Java文件中,可以定义多个类,
注意:public只能有一个,在有main方法的类前面加上,其他类不能加public
*/
public class MyTest {
public static void main(String[] args) {
Cat c = new Cat();
c.test("汤姆");
}
}
/*
变量的访问原则——就近原则:方法中要访问一个变量,会先在局部位置找,找到就使用
如果找不到,会找成员变量,找到就使用
*/
class Cat{
//成员变量
String name="发财";
//方法内部的变量和形参都属于局部变量
public void test(String name){
System.out.println(name);
}
}
此时test方法中需要输出name,先找局部变量,发现形参名字就为name,于是输出汤姆,而不会先去找成员变量。
而将代码改一下:
public class MyTest {
public static void main(String[] args) {
Cat c = new Cat();
c.test("汤姆");
}
}
class Cat{
//成员变量
String name="发财";
//方法内部的变量和形参都属于局部变量
public void test(String name1){
String name="杰克";
System.out.println(name);
}
}
此时test方法中需要输出name,先找局部变量,发现方法内部的变量name,于是输出杰克,而不会先去找成员变量。
2.
public class MyTest {
public static void main(String[] args) {
//基本数据类型,作为参数传递,形参的改变,不影响实参
//引用输入类型,作为参数传递,形参的改变,会影响实参
//引用数据类型:数组,类,接口
Dog dog = new Dog();
String name = "小白";
int age = 3;
//如果看到一个方法的形参,数据类型是类,那么就传一个该类的对象
dog.show(dog, name, age);
System.out.println(dog.name);
System.out.println(dog.age);
System.out.println(name);
System.out.println(age);
}
}
class Dog {
String name;
int age;
public void show(Dog d, String name, int age) {
name = "汪汪";
age = 2;
d.name = name;
d.age = age;
System.out.println(name);
System.out.println(age);
}
}
内存解析
五、匿名对象
(一)什么是匿名对象?
匿名对象:就是没有名字的对象,是对象的一种简化表示形式
(二)匿名对象应用场景
- 调用方法,仅仅只调用一次的时候
- 匿名对象可以作为实际参数传递
(三)匿名对象说明
- 匿名对象也是一个对象,具有对象的所有功能
- 每一次使用匿名对象时,都是一个新的对象,是不同的对象。
(四)匿名对象优点
- 由于匿名对象只在堆内存中开辟空间,而不存在栈内存的引用,所以匿名对象调用完就被垃圾回收器回收,提高了内存使用效率。
- 如果要执行的任务需要一个对象,但却不值得创建全新的对象(原因可能是所需的类过于简单,或者是由于它只在一个方法内部使用),匿名类就显得非常有用
(五)案例演示(匿名对象应用场景)
1.调用方法,仅仅只调用一次的时候。
public class MyTest {
public static void main(String[] args) {
//普通对象调用成员变量及方法
Cat c = new Cat();
c.age=3;
int age = c.age;
System.out.println(age);
c.eat();
//匿名对象调用成员变量及方法
int age1=new Cat().age;//匿名对象调用成员变量,每new一次就产生一个新的对象
System.out.println(age1);
new Cat().eat();//匿名对象的方法调用,每new一次就产生一个新的对象
}
}
class Cat{
int age=2;
public void eat(){
System.out.println("吃鱼");
}
}
- 问:为什么匿名对象只适合对方法的一次调用?
答:因为调用多次就会创建多个对象,每次调用都是不同的对象,那么就失去了实际意义,此时还不如用普通的有对象名的对象。
如果需要一个对象进行方法调用2次,使用匿名对象的方式无法实现:
new Cat().eat();
new Cat().eat();
这是2个Cat类的对象分别调用了eat()方法,而不是一个对象调用了两次方法。
- 问:匿名对象是否可以调用属性并赋值?有什么意义?
答:匿名对象可以调用属性并赋值,但是没有意义,无法再次使用,因为调用后就变成垃圾。如果需要赋值还是用有对象名的对象。语法上,匿名对象只创建对象,但是不用变量来接收。
2.匿名对象可以作为实际参数传递
public class MyTest {
public static void main(String[] args) {
Cat cat = new Cat();
//如果看到一个方法的形参的数据类型为类,那么就传一个该类的对象
cat.show(cat, 19);
System.out.println(cat.num);
System.out.println("---------------------");
//匿名对象可以作为参数传递
cat.show(new Cat(), 20);
System.out.println(cat.num);
}
}
class Cat {
int num = 100;
public void show(Cat cat, int num) {
cat.num = num;
System.out.println(cat.num);
}
}
六、封装(private关键字)
先来看一个例子:
public class Person {
String name;
int age;
public void show() {
System.out.println(name);
System.out.println(age);
}
}
public class MyTest {
public static void main(String[] args) {
Person p = new Person();
p.name="张三";
p.age=-10;
p.show();
}
}
本例通过 对象名.成员变量名=值
这种方式给成员变量设置值,但是不能排除一些不合理的数据,就比如年龄不可能为-10岁,我们希望能够对给成员变量设置的数据进行一些校验,那么我们就可以屏蔽掉 对象名.成员变量名=值
这种设置方式。
那么怎么屏蔽掉呢?可以使用关键字 private
。
(一)private关键字特点
- 是一个权限修饰符
- 可以修饰成员变量和成员方法
- 被其修饰的成员只能在本类中被访问
对比:public是一个权限修饰符,可以修饰类,可以修饰成员变量和成员方法,被修饰的成员在任何地方都可以访问。
案例演示
public class Person {
String name;
//private 是一个权限修饰符,私有的,可以修饰成员变量、成员方法,被修饰的成员,只能在本类中访问,外界无法访问。
private int age;//加上了private权限修饰符,私有成员变量
public void show() {
System.out.println(name);
System.out.println(age);
}
}
同理,如果成员方法前面的权限修饰符不是public而是private,那么该方法也无法在其他类中被调用。
成员变量被隐藏起来了无法被外界访问了,那么我们如何给创建的对象设置属性值呢?
这时我们就可以在定义的类中提供公共的访问方法,从而修改对象的属性。
public class Person {
String name;
private int age;//加上了private权限修饰符,私有成员变量
public void show() {
System.out.println(name);
System.out.println(age);
}
public void setName(String n) {//通过公共的set方法设置其属性
name = n;
}
public void setAge(int a) {//通过公共的set方法设置其属性
if(a>=0&&a<=120){//对数据进行校验
age = a;
}
else{
System.out.println("输入年龄不合逻辑!");
}
}
}
public class MyTest {
public static void main(String[] args) {
Person p = new Person();
p.name="张三";//依旧可以访问到name这个成员变量。
//p.age=-10;无法直接访问被private修饰的属性
p.setAge(10);//但可以通过公共的set方法设置其属性
p.show();
System.out.println("--------------");
Person p1 = new Person();
p1.setName("赵四");
p1.setAge(-10);
p1.show();
}
}
现在我们解决了设置私有属性的值的问题,那么假设我们需要获取对象的私有属性又该怎么办呢?
同样地,我们可以在类中提供公共的访问方式,返回该对象的属性值即可。
public class Person {
String name;
private int age;//加上了private权限修饰符,私有成员变量
public void setName(String n) {
name = n;
}
public void setAge(int a) {
if(a>=0&&a<=120){
age= a;
}
else{
System.out.println("输入年龄不合逻辑!");
}
}
public String getName() {//返回name
return name;
}
public int getAge() {//返回age
return age;
}
}
public class MyTest {
public static void main(String[] args) {
Person p = new Person();
p.name="张三";//依旧可以访问到name这个成员变量。
//p.age=-10;无法直接访问被private修饰的属性
p.setAge(10);//但可以通过公共的set方法设置其属性
String name=p.getName();//获取对象p的name
int age=p.getAge();获取对象p的age
System.out.println(name+" "+age);
Person p1 = new Person();
p1.setName("赵四");
p1.setAge(20);
String name1=p1.getName();
int age1=p1.getAge();
System.out.println(name1+" "+age1);
}
}
上述的几个例子就体现了封装的思想。
(二)封装概述
是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
(三)封装好处
- 隐藏实现细节,提供公共的访问方式
- 提高了代码的复用性
- 提高安全性。
(四)封装原则
将不需要对外提供的内容都隐藏起来。
把属性隐藏,提供公共方法对其访问。
七、this关键字
先来看一个例子:
假如set方法中,局部变量(形参)和成员变量同名了,那么当该set方法被调用时还会改变对象的属性值吗?
public class Person {
String name;
private int age;
public void setName(String name) {
name = name;
}
public void setAge(int age) {
age= age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void show(){
System.out.println(name+" "+age);
}
}
public class MyTest {
public static void main(String[] args) {
Person p = new Person();
p.setName("张三");
p.setAge(10);
p.show();
}
}
从结果我们发现输出并不是张三和10,证明该对象的属性并没有被修改,仍然是默认值。这是因为“就近原则”,set方法中的两个name都是指的局部变量(形参)的那个name,也即局部变量name自己赋给自己,并没有改变成员变量name,因此我们需要一个关键字this
来解决此问题:
public class Person {
String name;
private int age;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age= age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void show(){
System.out.println(name+" "+age);
}
}
public class MyTest {
public static void main(String[] args) {
Person p = new Person();
p.setName("张三");//p调用了set方法,那么set方法中的this就代表p。
p.setAge(10);
p.show();
}
}
(一)为什么要有this
当我们的局部变量和成员变量重名的时候,如果我们不使用this关键字,那么会导致一个问题:就是局部变量隐藏了成员变量的问题
(二)this关键字特点
是当前类的对象引用。
简单的记,它就代表当前类的一个对象。谁调用这个方法,那么该方法的内部的this就代表谁
public class MyTest {
public static void main(String[] args) {
A a = new A();
System.out.println(a);//a的地址
int num=10;
a.show(num,a);
System.out.println(num); //就近原则
}
}
class A{
int num=100;
public void show(int num, A a){
System.out.println(this);//与a的地址相同
System.out.println(num);//就近原则
System.out.println(a.num);
System.out.println(this.num);
System.out.println(a==this);//this实际上就相当于正调用该方法的对象
}
}
八、构造方法
假设有一个类A,那么创建一个A类对象:A a=new A();
,这个A()
其实是一个方法,叫做构造方法。
(一)构造方法概述和格式
- 构造方法概述和作用
创建对象,给对象中的成员进行初始化 - 构造方法格式特点
(1)方法名与类名相同
(2)没有返回值类型,连void都没有
(3)没有具体的返回值
(二)构造方法的重载
1.案例演示
构造方法的重载
public class Student {
String name;
int age;
//构造方法:方法名和类名相同,没有返回值类型,连void 也没有
//我们自定义的一个类中,即使不写构造方法,默认也会存在一个空参的构造方法
//构造方法,就是用来初始化这个类的,完成对类的实例化
public Student(){
System.out.println("无参构造方法执行了");
}
public Student(String name){//构造方法的重载
this.name=name;
System.out.println("一个参数的构造方法执行了");
}
public Student(String name,int age){//构造方法的重载
this.name=name;
this.age=age;
System.out.println("两个参数的构造方法执行了");
}
}
public class MyTest {
public static void main(String[] args) {
//类,是一个抽象的概念,不能直接使用,要使用类中的属性和功能,必须对类进行实例化(创建对象)
//我们在创建对象时,除了使用关键字new之外,还得借助构造方法,来完成对类的实例化。
//借助空参的构造方法创建对象
Student st1 = new Student();
System.out.println(st1.name);
System.out.println(st1.age);
//借助有参的构造方法创建对象
Student st2 = new Student("张三");
System.out.println(st2.name);
System.out.println(st2.age);
Student st3 = new Student("赵四", 20);
System.out.println(st3.name);
System.out.println(st3.age);
}
}
2.构造方法注意事项
- 如果我们没有给出构造方法,系统将自动提供一个无参构造方法。
- 如果我们给出了构造方法,系统将不再提供默认的无参构造方法。
注意:这个时候,如果我们还想使用无参构造方法,就必须自己给出。建议永远自己给出无参构造方法。
如下:
此时即使Dog类中没有写构造方法,创建Dog类的对象时也不会报错,因为默认存在一个无参构造方法。
但是如果我们给出了有参构造方法,那么默认的无参构造方法就没有了,此时若用无参构造方法创建对象会报错。
如果你还想要使用无参构造来创建对象,建议你手动写出来,也建议你永远手动写出来。
3.给成员变量赋值的两种方式
- setXxx()方法
- 构造方法
案例演示
public class Teacher {
//一个类的组成:构造方法、成员变量、成员方法
//私有成员变量
private String name;
private int age;
//提供有参、无参构造
public Teacher() {
}
public Teacher(String name, int age) {
this.name = name;
this.age = age;
}
//提供公共的 get set 方法
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 class MyTest {
public static void main(String[] args) {
//使用空参构造来创建对象
Teacher teacher = new Teacher();
//set方法给成员变量赋值
teacher.setName("张三");
teacher.setAge(18);
System.out.println(teacher.getName());
System.out.println(teacher.getAge());
//使用有参构造来创建对象,在创建对象的同时,就可以给成员变量赋值
Teacher teacher1 = new Teacher("李四", 35);
System.out.println(teacher1.getName());
System.out.println(teacher1.getAge());
}
}
九、创建一个对象的完整步骤
(1)加载.class文件进内存
(2)在栈内存为创建对象的变量开辟空间
(3)在堆内存为对象开辟空间
(4)给对象的成员变量进行默认初始化
(5)给对象的成员变量进行显式初始化
(6)通过构造方法给对象的成员变量赋值
(7)对象初始化完毕,把对象地址赋值给变量
案例演示
public class Student {
private String name="张三";
private int age=10;
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 class MyTest {
public static void main(String[] args) {
Student s = new Student("王五", 25);
//(1)加载Student.class文件进内存
//(2)在栈内存为s开辟空间
//(3)在堆内存为学生对象开辟空间
//(4)对学生对象的成员变量进行默认初始化
//(5)对学生对象的成员变量进行显式初始化
//(6)通过构造方法对学生对象的成员变量赋值
//(7)学生对象初始化完毕,把对象地址赋值给s变量
}
}
练习:
定义一个长方形(Rectangle)类,定义求周长和求面积的方法,然后定义一个测试类,进行测试。
public class Rectangle {
private double length;
private double width;
public Rectangle(double length,double width){//有参构造
this.length=length;
this.width=width;
}
public double getPerimeter(){//求周长
return 2*length+2*width;
}
public double getArea(){//求面积
return length*width;
}
}
public class RectangleDemo {
public static void main(String[] args){
Rectangle rectangle = new Rectangle(2.5, 4.2);
System.out.println("周长为:"+rectangle.getPerimeter());
System.out.println("面积为:"+rectangle.getArea());
}
}
十、static关键字
(一)static关键字的引入
案例
public class Person {
public String name;
//我想定义一个全是中国人的类
//我想让中国这个数据变成共享变量,让这个类的所有对象,都能够共享它
//我们可以使用一个关键字,static 静态的 可以修饰成员变量和成员方法
//被static所修饰的成员变量,是一个共享变量,被类的所有对象所共享
//被static所修饰的成员叫作静态成员,它随着类的加载而加载(随着.class文件加载进内存,静态成员就会加载)
//静态成员优先于对象而存在
public static String country = "中国";
}
public class MyTest {
public static void main(String[] args) {
Person person = new Person();
person.name="张三";
person.country="美国";
Person person2 = new Person();
person2.name = "李四";
person2.country = "新加坡";//因为静态成员变量共享,所以修改它,每个对象的该成员变量同时改变
System.out.println(person.name+"----"+person.country);
System.out.println(person2.name + "----" + person2.country);
}
}
注意:类一加载,静态成员就存在了。(静态成员随着类的加载而加载)
(二)static关键字的特点
(1)随着类的加载而加载
(2)优先于对象存在
(3)被类的所有对象共享
举例:一个班级的学生应该共用同一个班级编号。
其实这个特点也是在告诉我们什么时候使用静态
如果某个成员变量是被所有对象共享的,那么它就应该定义为静态的。
(4)可以通过类名调用
其实它本身也可以通过对象名调用,但推荐使用类名调用。
静态修饰的内容一般我们称其为:与类相关的、类成员
案例演示
public class MyTest {
public static void main(String[] args) {
//A a = new A();
//int b = a.b;
//通过 对象名.共享变量名 这种方式,去访问共享变量不报错,但不推荐使用
//被static 所修饰的我们推荐使用类名直接调用
//因为静态变量,属于类,所以使用类名直接调用即可
A.b=500;
int b = A.b;
System.out.println(b);
//a.show(); 不推荐使用
A.show();//静态方法,推荐使用类名直接调用
}
}
class A{
int a=100;
static int b=1000; //静态变量(共享变量)
public static void show(){//静态方法
System.out.println("这是一个静态的show方法");
}
}
(三)static的注意事项
(1)在静态方法中是没有this关键字的
如何理解呢?
静态是随着类的加载而加载的,this是随着对象的创建而存在的。
因此,静态比对象先存在。
(2)静态方法只能访问静态成员变量和静态成员方法;而非静态方法不仅可以访问静态成员变量和静态成员方法,还能访问非静态成员变量和非静态成员方法。
简单记:静态只能访问静态,非静态可以访问静态的也可以访问非静态的。
案例演示
public class MyTest {
public static void main(String[] args) {
}
}
class B{
int a=10;
static double num=100;
//非静态方法,既可以访问静态变量,也可以访问非静态变量
public void show(){
System.out.println(a);
System.out.println(num);
}
//静态方法
public static void staticShow(){
//System.out.println(a);报错,不能访问非静态变量
System.out.println(num);
}
//非静态方法,既可以访问静态方法,也可以访问非静态方法
public void test() {
this.show();
staticShow();
}
//静态方法,只能访问静态方法
public static void test2() {
//show();报错
//this.staticShow();报错
//静态方法里面,不能存在this,this代表一个对象,对象是后来才有的,先有的,不能访问后有的
staticShow();
}
}
注意:main方法也是静态方法,main方法中调用的方法也必须得是静态方法,否则无法直接调用。
(四)静态变量和成员变量的区别
(1)所属不同
静态变量属于类,所以也称为类变量
成员变量属于对象,所以也称为实例变量(对象变量)
(2)内存中位置不同
静态变量存储于方法区中的静态区
成员变量存储于堆内存
(3)内存出现时间不同
静态变量随着类的加载而加载,随着类的消失而消失
成员变量随着对象的创建而存在,随着对象的消失而消失
(4)调用不同
静态变量可以通过类名调用,也可以通过对象调用(不推荐)
成员变量只能通过对象名调用
拓展:Math类的随机数功能
(一)Math类概述
Math类包含用于执行基本数学运算的方法
(二)Math类特点
由于Math类在java.lang包下,所以不需要导包。
没有构造方法,因为它的成员全部是静态的(可以直接用类调用方法,不需要创建对象)。
(三)获取随机数的方法
public static double random();
返回带正号的 double 值,该值大于等于 0.0 且小于 1.0。
案例演示
获取十个1-100之间的随机整数(包括1和100)
public class MyTest {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
//直接用类调用方法
int num=(int)(Math.random()*100+1);//强制转换为整型
System.out.println(num);
}
}
}