成员变量与局部变量
成员变量和局部变量的区别?
1.在类中的位置不同
- 成员变量:在类中方法外
- 局部变量:在方法定义中或者方法声明上。
2.在内存中的位置不同
- 成员变量: 在堆内存
- 局部变量: 在栈内存
3.生命周期不同
* 成员变量:随着对象的创建而存在,随着对象的消失而消失
* 局部变量:随着方法的调用而存在,随着方法的调用完毕而消失。
4.初始化值不同
* 成员变量:有默认初始化值
* 局部变量:没有默认初始化值,必须定义,赋值,然后才能使用
注意事项:
局部变量名称可以和成员变量名称一样,在方法中使用的时候,采用的是就近原则。
/*
成员变量和局部变量的区别?
A:在类中的位置不同
成员变量:在类中方法外
局部变量:在方法定义中或者方法声明上。
*/
class Variable
{
//成员变量
//int num = 10;
int num;//
public void show()
{
//int num2 = 20;//局部变量
//int num1;//没有默认值
int num1 = 10;
System.out.println(num1);
//int num = 100;
System.out.println(num);
}
}
public class VariableDemo {
public static void main(String[] args)
{
Variable v = new Variable();
System.out.println(v.num);//访问成员变量
v.show();
}
}
形式参数的问题
- 基本类型:形式参数的改变不影响实际参数
- 引用类型:形式参数的改变直接一影响实际参数
引用类型包括:类,数组,接口类型
形式参数是基本类型
//形式参数是基本类型
class Demo{
public int sum (int a, int b)
{
return a+b;
}
}
//形式参数是引用类型
class Student{
public void show(){
System.out.println("我爱学习");
}
}
class StudentDemo{
//如果你看到了一个方法的形式参数是一个类类型(引用类型),
//这里其实需要的是该类的对象。
public void method(Student s){
//调用的时候,把main方法中s的地址传递调到了这里
//Student s = new Student();
s.show();
}
}
public class ArgsTest {
public static void main(String[] args)
{
//形式参数是基本类型的调用
Demo d = new Demo();
int result = d.sum(10,20);
System.out.println("result = "+result);
//形式参数是引用类型的调用
//需求:我要调用StudentDemo类中的method()方法
StudentDemo sd = new StudentDemo();
//创建学生对象
Student s = new Student();
sd.method(s);//把s的地址给到了这里
}
}
匿名对象
匿名对象就是没有名字的对象
- 是对象的一种简化表示形式
匿名对象的两种使用情况
- 对象调用方法仅仅一次的时候
注意:
调用多次的时候不适合。那么,这种匿名调用有什么好处吗?
有,匿名对象调用完毕后就是垃圾。 可以被垃圾回收器回收。 - 作为实际参数传递
class Student {
public void show()
{
System.out.println("我爱学习");
}
}
class StudentDemo{
public void method(Student s)
{
s.show();
}
}
public class NoNameDemo {
public static void main(String[] args)
{
//带名字的调用
Student s = new Student();
s.show();
s.show();
System.out.println("------------");
//****匿名对象****
//new Student();
//匿名对象调用方法
new Student().show();
new Student().show();//这里其实是重新创建了一个新的对象
//匿名对象作为实际参数传递
StudentDemo sd = new StudentDemo();
//Student ss = new Student();
//sd.method(ss);//这里的ss是一个实际参数
//sd.method(new Student());//
//匿名对象
sd.method(new Student());
//再来一个
new StudentDemo().method(new Student());
}
}
封装概述
我们在使用这个案例的过程中,发现了一个问题
通过对象去给成员赋值,可以赋值一些非法的数据
这是不合理的
应该是这个样子的:在赋值之前,先对数据进行判断
判断到底在哪里做比较合适呢?
Student类是一个测试类,测试类一般指创建对象,调用方法。
所以,这个判断应该定义在Student1类中
而我们在成员变量的位置,可不可以进行判断呢?
逻辑语句是应该定义在方法中的,所以,我们最终决定在Student类中
提供一个方法来对数据进行校验
按照我们前面的分析,我们给出了一个方法进行校验
但是呢,她偏偏不调用方法来赋值,还是直接赋值了
这样我们的方法就没有起到作用。
我就应该要求你必须使用我的方法,而不能直接调用成员变量赋值
怎么去强制要求不能直接使用成员变量呢?
针对这种情况java就提供了关键字private
private:私有的,可以修饰成员变量和成员方法
/*
定义一个学生类:
成员变量:name,age
成员方法:show()方法
*/
class Student1{
//姓名
String name;
//年龄
int age;
//写一个方法对数据进行校验
/*
* 返回值类型: void
* 参数列表:int age
*/
public void SetAge(int a)
{
if(a<0||age>120)
{
System.out.println("你给的年龄有问题");
}
else
{
age = a ;
}
}
//show()方法,显示 所有成员变量值
public void show()
{
System.out.println("姓名:"+name);
System.out.println("年龄:"+age);
}
}
public class Student {
public static void main(String[] args)
{
//创建学生对象
Student1 s = new Student1();
s.show();
System.out.println("----------");
//给成员变量赋值
s.name="罗巍";
s.age = 23;
s.show();
System.out.println("----------");
//给age赋值
s.SetAge(-27);//这个数据是不合理的
s.show();
System.out.println("----------");
}
}
注意:被private修饰的成员只能在本类中访问。
其实到现在我讲解的是一个封装的思想。
封装的基本概念
影藏对象的属性和实现细节,仅对外提供公共访问方式。
封装的好处
- 影藏实现细节,提供公共的访问方式
- 提高了代码的复用性
- 提高安全性
封装原则
- 将不需要对外提供的内容都隐藏起来。
- 把属性影藏,提供公共方式对其提问。
private关键字
- 是一个关键字
- 可以修饰成员(成员变量和成员方法)
- 被private修饰的成员只在本类中才能访问
private:
是一个权限修饰符
可以修饰成员变量和成员方法
被其修饰的成员只能在本类中被访问
class Demo{
//int num =10;
//用private修饰
private int num = 10;
public void show()
{
System.out.println(num);
}
private void method(){
System.out.println("method");
}
public void function()
{
method();
}
}
public class PrivateDemo {
public static void main(String[] args)
{
Demo d = new Demo();
//不能方法私有的成员变量
//System.out.println(d.num);
d.show();
d.function();
}
}
private的标准用例
private最常见的应用
- 把成员变量用private修饰
- 提供对应的getXxx()setXxx()方法
作业
请把手机类写成一个标准类,然后创建对象测试功能
手机类:成员变量:
品牌:String brand;
价格:int price;
颜色:String color;
成员方法:
针对每一个成员变量给出对应getXXX()/setXxx()方法。
最后定义测试:
创建一个对象,先通过getXxx()方法输出成员变量的值。这一次的结果是:null—0—null
然后通过setXxx()方法给成员变量赋值。再次输出结果。这一次的结果是:三星—2999—土豪金
class phone{
//品牌
private String brand;
//价格
private int price;
//颜色
private String color;
//Get()和Set()方法
public String getBrand()
{
return brand;
}
public void setBrand(String brand)
{
this.brand = brand;
}
public int getPrice()
{
return price;
}
public void setPrice(int price){
this.price = price;
}
public String getColor()
{
return color;
}
public void setColor(String color)
{
this.color = color;
}
}
public class PhoneTest {
public static void main(String[] args)
{
phone s = new phone();
System.out.println(s.getBrand()+"---"+s.getPrice()+"---"+s.getColor());
phone s1 = new phone();
s1.setBrand("三星");
s1.setPrice(2999);
s1.setColor("土豪金");
System.out.println(s1.getBrand()+"---"+s1.getPrice()+"---"+s1.getColor());
}
}
构造方法
构造方法作用: 给对象的数据进行初始化
格式:
A:方法名与类名相同
B : 没有返回值类型,连void都没有
C :没有具体的返回值
class Student{
private String name;//null
private int age;//0
public Student()//这就是构造方法
{
System.out.println("这是构造方法");
}
}
public class ConstructDemo {
public static void main(String[] args)
{
//创建对象
Student s = new Student();
System.out.println(s);
}
}
构造方法的重载及注意事项
构造方法的注意事项:
- 如果我们没有给出构造方法,系统将自动提供一个无参构造方法
- 如果我们给出了构造方法,系统将不再提供一个默认的无参构造方法。
注意:这个时候如果我们还想使用无参数构造的方法,就必须自己给出。建议永远自己给出无参构造方法。
class Student1{
private String name;
private int age;
public Student1() //构造方法必须要与类名相同
{
System.out.println("这是无参构造方法");
}
//构造方法的重载格式
public Student1(String name)
{
System.out.println("这是带一个String类型的构造方法");
this.name = name;
}
public Student1(int age)
{
System.out.println("这是带一个int类型的构造方法");
this.age = age;
}
public Student1(String name,int age)
{
System.out.println("这是一个带多个参数的构造方法");
this.name = name;
this.age = age;
}
public void show()
{
System.out.println(name+"---"+age);
}
}
public class ConstructDemo2 {
public static void main(String[] argsw)
{
//创建对象
Student1 s = new Student1();
s.show();
System.out.println("--------");
//创建另一个对象
Student1 s2 = new Student1("林青霞");
s2.show();
System.out.println("--------");
//创建对象3
Student1 s3 = new Student1(19);
s3.show();
System.out.println("--------");
//创建对象4
Student1 s4 = new Student1("林青霞",12);
s4.show();
System.out.println("--------");
}
}
由上可知:
给成员变量赋值有两种方式
1. setXxx()方法
2. 构造 方法
一个基本类的标准代码写法
//一个标准代码的最终版
//学生类:
//成员变量:NAME,AGE
//构造方法:无参,带两个参数
//成员方法:GETXXX()/SETXXX()
// SHOW();输出该类的所有成员变量值
//给成员变量赋值的方式有两种:
//A:setXxx()方法
//B:构造方法
//输出成员变量的方式
//A:通过getXxx()分别获取然后拼接,一般都是靠拼接做的
//B:通过show()方法
class Student3{
//姓名
private String name;
//年龄
private int age;
//构造方法
public Student3(){
}
public Student3(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 void show()
{
System.out.println(name+"--"+age);
}
}
public class StudentDemo {
public static void main(String[] args)
{
//方式1给成员变量赋值
//无参构造方法+setXxx()
Student3 s1 = new Student3();
s1.setName("罗巍");
s1.setAge(90);
//输出值
System.out.println(s1.getName()+"--"+s1.getAge());
s1.show();
//方式2给成员变量赋值
Student3 s2 = new Student3("罗巍",23);
System.out.println(s2.getName()+"--"+s2.getAge());
s2.show();
}
}
面向对象练习
练习1 定义一个类Demo,其中定义一个求两个数据和的方法,定义一个测试了Test,进行测试。
class Demo{
// private int a;
// private int b;
//
// //创建构造方法
// public Demo(int a ,int b){
// this.a = a;
// this.b = b;
// }
// public int sum(int a ,int b)
// {
// return a+b;
// }
// public void show()
// {
// System.out.println("sum = "+(a+b));
// }
// 虽然这种方法可以,并且好像是符合了面向对象的思想,但是不好
// 因为我们曾经说过:类是一组相关的属性和行为的集合,并且是通过食物转换过来的
// 而类中的成员变量就是食物的属性,属性是用来描述事物的
// 同理:成员变量其实就是用来描述类的
public int sum(int a ,int b)
{
return a+b;
}
}
public class Test {
public static void main(String[] args)
{
//创建对象
Demo s = new Demo();
// s.show();
System.out.println(s.sum(4,5));
}
}
因此:
变量什么时候定义维成变量:
如果这个变量是用来描述这个类的信息的,那么,该变量就应该定义为成员变量。
变量到底定义在大范围好还是小范围好:
变量的范围是越小越好,因为能被及时的被回收。
练习2 定义一个长方形类,求周长和面积的方法,然后定义一个测试类Test,进行测试。
长方形的类:
成员变量:长,宽
成员方法:
1. 求周长:(长+宽)*2
2. 求面积: 长*宽
注意:import 必须出现在所有类型的前面
import java.util.*; //import必须出现在所有类的前面
class ChangFangXing{
//长方形的长
private int length;
//长方形的高
private int width;
public ChangFangXing(){ }
// public int getLength()
// {
// return length;
// }
//仅提供setXxx()既可
public void setLength(int length)
{
this.length = length;
}
public void setWidth(int width)
{
this.width = width;
}
//求周长
public int getZhouchang(){
return (length+width)*2;
}
//求面积
public int getArea(){
return length*width;
}
// PUBLIC VOID CANDS(INT CHANG,INT KUAN){
// INT S = CHANG*KUAN;
// INT C = (CHANG+KUAN)*2;
// }
}
public class Squretest {
public static void main(String[] args)
{
//创建键盘录入对象
Scanner sc = new Scanner(System.in);
System.out.println("请输入长方形的长:");
int length = sc.nextInt();
System.out.println("请输入长方形的宽:");
int width = sc.nextInt();
//创建对象
ChangFangXing s = new ChangFangXing();
s.setLength(length);
s.setWidth(width);
System.out.println("周长是:"+s.getZhouchang());
System.out.println("面积是:"+s.getArea());
}
}
练习三 定义一个员工类,自己分析出几个成员,然后给出成员变量,构造方法,getXxx() setXxx()方法,以及一个显示有成员信息的方法
分析:
员工
* 成员变量:员工编号、姓名、年龄
* 构造方法:无参构造方法
* 成员方法:getXxx()/setXxx();show()
import java.util.Scanner;
class empo{
private String name;
private int age;
private String gender;
private String work;
//构造方法
public empo(){}
//获取name
public String GetName()
{
return name;
}
//设置name
public void setName(String name){
this.name = name;
}
//age
public int getAge(){
return age;
}
public void setAge(int age)
{
this.age = age;
}
//gender
public String getGender()
{
return gender;
}
public void setGender(String gender)
{
this.gender = gender;
}
//work
public String getWork()
{
return work;
}
public void setWork(String work)
{
this.work = work;
}
public void show()
{
System.out.println("员工信息:姓名 "+name+" 年龄 "+age+" 性别 "+ gender+"工作"+work);
}
}
public class test {
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
System.out.println("请输入员工的姓名");
String name = sc.nextLine();
System.out.println("请输入员工的年龄");
int age = Integer.parseInt(sc.nextLine());
System.out.println("请输入员工的性别");
String gender = sc.nextLine();
System.out.println("请输入员工的工作");
String work = sc.nextLine();
empo s = new empo();
s.setName(name);
s.setAge(age);
s.setGender(gender);
s.setWork(work);
s.show();
}
}
练习四 定义一个MyMath,提供基本的加减乘除功能,然后进行测试。
import java.util.Scanner;
class MyMath{
//成员变量
private int a;
private int b;
//构造方法
public MyMath(){
}
//加法
public void getAdd(){
System.out.println("两者的相加结果为a+b = "+(a+b));
}
public void setNum(int a, int b)
{
this.a = a;
this.b = b;
}
//减法
public void getSub(){
System.out.println("两者的相减结果为a-b = "+(a-b));
}
//乘法
public void getMul(){
System.out.println("两者的相乘结果为a*b = "+(a*b));
}
//除法
public void getDiv(){
System.out.println("两者的相除结果为a/b = "+(a/b));
}
}
public class test2 {
public static void main(String[] args)
{
Scanner s1 = new Scanner(System.in);
System.out.println("请输入第一个数字");
int a = s1.nextInt();
System.out.println("请输入第二个数字");
int b = s1.nextInt();
//创建对象
MyMath s = new MyMath();
s.setNum(a, b);
s.getAdd();
s.getDiv();
s.getMul();
s.getSub();
}
}
static 关键字的引入
class Person{
//姓名
String name;
//年龄
int age;
//国籍
String country;
public Person(){}
public Person(String name,int age){
this.name = name;
this.age = age;
}
public Person(String name,int age,String country)
{
this.name = name;
this.age = age;
this.country = country;
}
public void show(){
System.out.println("姓名:"+name+",年龄:"+age+",国籍:"+country);
}
}
public class PersonDemo {
public static void main(String[] args){
//创建对象
Person p1 = new Person("罗巍",18,"中国");
p1.show();
//创建对象2
Person p2 = new Person("杨幂",22,"中国");
p2.show();
//创建对象3
Person p3 = new Person("凤姐",20,"中国");
p2.show();
}
}
姓名和年龄都是变化的,这个我能接受,因为每个人的姓名和年龄是不同的
但是我们现在选取的人都是中国人,他们的国籍是一样的
一样的国籍,我每次创建对象,再堆内存都要开辟这样的空间
我就觉得有点浪费了:怎么办呢?针对多个对象有共同的成员变量值的时候,
java提供了一个关键字来修饰:static
static的特点
它可以修饰成员变量,还可以修饰成员方法
* 随着类的加载而加载(回想main方法)
* 优先于对象存在
* 被所有对象共享 举例:我们班的学生应该公用同一个班级编号。其实这个特点也是再告诉我们什么时候使用静态。如果某个成员变量是被所有对象共享的,那么他就应该定义为静态的。
* 可以通过类名调用 其实它本身也可以通过对象名调用。
推荐使用类名调用静态修饰的内容一般我们称其为:与类相关的,类成员
class Student{
//非静态变量
int num = 10;
//静态变量
static int num2 = 20;
}
public class StudentDemo {
public static void main(String[] args)
{
Student s = new Student();
System.out.println(s.num);
System.out.println(Student.num2);
System.out.println(s.num2);
}
}
static关键字的注意事项
- 在静态方法中是没有this关键字的
如何理解呢:
应为静态是随着类的加载而加载,this是随着对象的创建而存在。镜像比对象先存在。 静态方法只能访问静态的成员变量和静态的成员方法
。- 静态方法:
成员变量:只能访问静态变量
成员方法:只能访问静态成员方法 - 非静态方法:
成员变量:可以是静态的,也可以是非静态的。
成员方法:可以是静态的成员方法,也可以是非静态的成员方方法。
- 静态方法:
简单记:
静态只能访问静态
main方法是静态的
main方法的格式讲解:
public static void main(String[] args){….}
public :公共的,访问权限是最大的由于main方法是被jvm调用,所以权限要够大
static:静态的,不需创建对象,通过类名就可以。方便jvm的调用
void:没有返回值,因为我们曾今说过,方法的返回值是返回调用者,而main方法是被jvm调用。你反悔内容给jvm没有意义。
main():是一个常见的方法入口,所有语言都是以main作为入口。
String[] args:这是一个字符串数组。值去哪里了?
这个值早期是为了接收键盘录入的数据的。格式是:java MainDemo hello world java