this关键字
在java中,this关键字是一个最重要的概念。使用this关键字可以完成以下的操作:
- 调用类中的属性
- 调用类中的方法或构造方法
- 表示当前对象:在方法被调用的过程中,哪个对象调用了方法,在方法内的this就表示谁
- 可以使用当前的类名.this
public class Test2{
public static void main(String[] args){
Cat cat = new Cat();
cat.setName("咪咪");
cat.setAge(3);
cat.eat();
}
}
class Cat{
//属性的封装
private String name;//成员变量,在类中定义
private int age;//成员变量,在类中定义
//getter and setter
//对外提供一个对name属性设值的方法
public void setName(String name){//name=咪咪
this.name=name;//this代表的是当前对象
}
//对外提供一个获取name属性的方法
public void getName(String name){
return name;
}
//对外提供一个对age属性设值的方法
public void setAge(int age){
this.age=age;
}
//对外提供一个获取age属性的方法
public void getAge(int age){
return age;
}
public void eat(){
//在方法中使用this调用类中的其它方法或属性,this可以省略
System.out.println("我是"+this.getName()+",我爱吃鱼")
//System.out.println("我是"+Cat.this.getName()+",我爱吃鱼")
//System.out.println("我是"+Cat.this.name()+",我爱吃鱼")
}
}
}
值传递与引用传递
引用传递的本质是传递内存空间地址,而非值本身,通过内存图充分理解栈内存和堆内存
- 值传递
public class ValueDemo{
public static void main(String[]args){
int x = 10;
method(x);
System.out.println("x="+x);
}
public static void method(int mx){
mx=20;
}
}
2. 引用传递
public class RefDemo1{
public static void main(String[] args){
Duck d = new Duck();
method(d);
System.out.println("Duck age="+d.age);
}
public static void method(Duck duck){
duck.age=5;
}
}
class Duck{
int age=2;//省略封装
}
- String 传递
字符串本身就是一个对象
public class RefDemo2{
public static void main(String[] args){
String name="小飞";
method(name);
System.out.println("name="+name);
}
public static void method(String sname){
sname="小备";
}
}
4. String 传递
public class RefDemo3{
public static void main(String[] args){
Person p=new Person();
method(p);
System.out.println("person name="+p.name);
}
public static void method(Person p){
p.name="备备";
}
}
class Person{
String name="飞飞";//省略封装
}
对象的一对一关系
表达对象的一对一关系,其实就是把对象类型作为属性定义
两个对象之间的一对一关系:
比如:
一个英雄(Hero)对一个兵器(Weapon)
代码如何表示?
双向一对一
单向一对一
public class Test5{
public static void main(String[] args){
Hero hero=new Hero("刘备",300);
Weapon weapon = new Weapon("双股剑",3);
//把两个对象关联起来
hero.setWeapon(weapon);
weapon.setHero(hero);
//通过英雄来获取他的信息
String name=hero.getName();
int age=hero.getAge();
Weapon w=hero.getWeapon();
System.out.println("我是"+name+",我"+age+"岁,我的武器是: "+w.getName()+",排行"+w.getGrade()+"级");
}
}
//英雄类
class Hero{
private String name;
private int age;
private Weapon weapon;//一对一
public void setWeapon(Weapon weapon){
this.weapon=weapon;
}
public Weapon getWeapon(){
return weapon;
}
public Hero(){}
public Hero(String name,int age){
this.name=name;
this.age=age;
}
public void setName(String name){
this.name=name;
}
public String getName(int age){
return name;
}
public void setAge(int age){
this.age=age;
}
public int getAge(){
return age;
}
}
//兵器类
class Weapon{
private String name;
private int grade;
public Weapon(){}
public Weapon(String name,int grade){
this.name=name;
this.grade=grade;
}
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void setGrade(int grade){
this.grade=grade;}}
static关键字
静态变量的使用
static作用大,内存只有独一份,同类对象都共享,三种用法各不同,谨记静态初始化,它与对象创建没关系
static关键字的作用:
1.使用static关键字修饰一个属性
声明为static的变量实质上就是全局变量
2.使用static关键字修饰一个方法
通常,在一个类中定义一个方法为static,那就是说,无需本类的对象即可调用此方法
3.使用static关键字修饰一个类(内部类)
4.静态变量或方法不属于对象,依赖类
5.静态变量是全局变量,生命周期从类被加载后一直到程序结束
6.静态变量只存一份,在静态方法区中存放
7.静态变量是本来所有对象共享一份
8.建议不要使用对象名去调用静态数据,直接使用类名调用
9.static修是一个方法,那么该方法属于类,不属于对象,直接用类名调用
10.静态方法不能访问非静态属性和方法,只能访问静态的
public class Test6{
public static void main(String[] args){
Role beibei=new Role("刘备","蜀国");
Role yunchang =new Role("云长","蜀国");
Role feifei=new Role("张飞","蜀国");
System.out.println(beibei.geiInfo());
System.out.println(yunchang.geiInfo());
System.out.println(feifei.geiInfo());
}
}
class Role{
private String name;
private String country;
public Role(String name,String country){
this.name=name;
this.country=country;
}
public void setName(String name){
this.name=name;
}
public String getName(){
return name;}
}
public void setCountry(String country){
this.country=country;
}
public String getCountry(){
return country;
public String getInfo(){
return "name="+name+",country="+country;}
}
public class Test6{
public static void main(String[] args){
Role beibei=new Role("刘备");
Role yunchang =new Role("云长");
Role feifei=new Role("张飞");
System.out.println(beibei.geiInfo());
System.out.println(yunchang.geiInfo());
System.out.println(feifei.geiInfo());
}
}
class Role{
private String name;
private static String country="蜀国";//静态变量(全局变量)
public Role(String name,String country){
this.name=name;
this.country=country;
}
public void setName(String name){
this.name=name;
}
public String getName(){
return name;}
}
public void setCountry(String country){
this.country=country;
}
public String getCountry(){
return country;
public String getInfo(){
return "name="+name+",country="+Test6.country;}
}
内存结构
理解内存结构图,在开发中,定义静态数据需要充分考虑数据的生命周期,如果静态数据太多,必然会占用更多的内存空间
声明为static的方法有以下几条限制:
- 它们仅能调用其他的static方法
- 它们只能访问static数据
- 它们不能以任何方式引用this或super
什么时候使用static? - 所有对象共同的属性或方法,那么我们应该定义为静态的
main方法分析
/**
主方法:
public static void main(String[] args){
//代码块
}
*/
- public:公有的,最大的访问权限
- static:静态的,无需创建对象
- void:表示没有返回值,无需向JVM返回结果
- main:方法名,固定的方法名
- Stringp[] args:表示参数为字符串数组,可以在调用方法时传入参数
代码块
理解代码块的作用以及实初始化的过程,注意仅,静态代码块可在未来开发中用来作启动项目时需要初始化数据的工作
- 普通代码块
直接写在方法中的代码块就是普通代码块
示例:
public class Demo1{
public static void main(String []args){
{//普通代码块
String info="局部变量-1";
System.out.println(info);
}
String info = "局部变量-2";
System.out.println(info);
}
}
- 构造块,是在类中定义的代码块,在创建对象时被调用,优于构造方法执行
示例
public class Test7 {
public static void main(String[] args){
Student s=new Student();
Student s1=new Student();
}
}
class Student{
public Student(){
System.out.println("我是构造方法");
}
{
System.out.println("我是构造代码块");
}
public void study(){
//限制作用域
{
int i = 10;
System.out.println("我是普通代码块");
}
}
}
- 静态代码块
在类中使用static声明的代码块称为静态代码块
在第一次使用的时候被调用(创建对象),只会执行一次优于构造块执行,我们在项目开发中,通常会使用静态代码块来初始化只调用一次的数据。比如说:
public class Test7 {
public static void main(String[] args){
Student s=new Student();
Student s1=new Student();
}
}
class Student{
static {
System.out.println("我是静态代码块");
}
public Student(){
System.out.println("我是构造方法");
}
{
System.out.println("我是构造代码块");
}
public void study(){
//限制作用域
{
int i = 10;
System.out.println("我是普通代码块");
}
}
}
- 同步代码块(多线程)
小结:重点会使用的是静态代码块,普通代码块、同步代码块、构造代码块很少用到
单例设计模式
单例模式的思想在于保证工具类仅有一个实例,以节省工具类在频繁使用时不断创建对象消耗内存的场景
单例设计模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点
- 构造方法私有化
- 声明一个本类对象
- 给外部提供一个静态方法获取对象实例
两种实现方式: - 饿汉式
- 懒汉式
在项目中为什么要使用单例,单例有什么好处? - 在设计一些工具类的时候(通常工具类,只有功能方法,没有属性)
- 工具类可能会被频繁调用
目的是为了节省重复创建对象所带来的内存消耗,从而来提高效率
能不能使用构造方法私有化+静态方法来替代单例
public class Test8 {
public static void main(String[] args){
Singleton2 s=Singleton2.getInstance();
s.print();
Singleton2 s2=Singleton2.getInstance();
s2.print();
System.out.println(s==s2);
}
}
//使用构造方法私有化+静态方法来实现工具类 比如Math
class Tools{
private Tools(){};
public static void print1(){
}
public static void print2(){
}
}
//饿汉式:在类被加载后,对象被创建,到程序结束后释放,占用内存时间长,提高效率
class Singleton1{
private Singleton1(){}
private static Singleton1 s = new Singleton1();
public static Singleton1 getInstance(){
return s;
}
public void print(){
System.out.println("测试方法");
}
}
//懒汉式:在第一次调用getInstance方法时,对象被创建,到程序结束后释放
//占用内存的时间短,效率低
//在多线程访问时会有安全问题
class Singleton2{
private Singleton2(){};
private static Singleton2 s;
public static Singleton2 getInstance(){
if (s==null){
s = new Singleton2();
}
return s;
}
public void print(){
System.out.println("测试方法");
}
}
对象数组与管理
这是一个非常重要的案例,重点要掌握动态数组的思想,为后续理解集合框架中的ArrayList源码作好铺垫
1.对象数组就是数组里的每个元素都是类的对象,赋值时先定义对象,然后将对象直接赋给数组
示例
Chicken[] cs=new Chicken[10];
使用对象数组实现多个Chicken的管理
动态数组的本质其实是通过创建新数组来实现无线扩容,理解扩容算法和删除算法是掌握动态数组的关键
动态数组:
- 数组是一种线性数据结构
- 数组不适合作删除插入等操作,适合添加、查找、遍历
import java.util.Arrays;
public class Test9 {
public static void main(String[] args){
ChickenManager cm=new ChickenManager(5);
//添加
cm.add(new Chicken(1,"小小",4));
cm.add(new Chicken(2,"小二",5));
cm.add(new Chicken(3,"小红",6));
cm.add(new Chicken(4,"小秦",7));
cm.add(new Chicken(5,"小刚",8));
cm.add(new Chicken(6,"小qi",8));
System.out.println("数组的长度是:"+cm.length());
System.out.println("-----------------findALL-----------------");
cm.printAll();
System.out.println("-----------------find-----------------");
Chicken c=cm.find(5);
c.print();
System.out.println("------------------update----------------");
cm.update(new Chicken(1,"下蛋公鸡",20));
cm.printAll();
}
}
//小鸡管理类
class ChickenManager{
private Chicken[] cs = null;
private int count = 0;//记录当前数组的元素个数(下标)
public ChickenManager(int size){
if (size>0){
cs=new Chicken[size];
}else{
cs=new Chicken[5];
}
}
public int length(){
return cs.length;
}
//添加实现动态数组
public void add(Chicken c){
if (count>=cs.length){//数组已满,需要扩充
//算法1:扩充原来数组大小的一半 cs.length*3/2+1
//算法2:扩充原来数组的一倍cs.length*2
int newLen = cs.length*2;
cs=Arrays.copyOf(cs,newLen);
}
cs[count]=c;
count++;
}
//删除
public void delete(int id){
for (int i=0;i<count;i++){
if (cs[i].getId()==id){
//找到了要删除的对象,把该对象之后的对象向前移动一位
for (int j=i;j<count-1;j++){
cs[j]=cs[j+1];
}
//把最后一个对象赋值为空(删除)
cs[count-1]=null;
count--;//下标减一
break;
}
}
}
//更新
public void update(Chicken c){
Chicken temp=find(c.getId());
if (temp!=null){
temp.setName(c.getName());
temp.setAge(c.getAge());
temp.setId(c.getId());
}
}
//查找
public Chicken find(int id){
for (int i=0;i<count;i++){
if (cs[i].getId()==id){
return cs[i];
}
}
return null;
}
//输出所有
public void printAll(){
for (int i=0;i<count;i++){
cs[i].print();
}
}
}
//小鸡类(数据对象) value object(VO)
class Chicken{
private int id;
private String name;
private int age;
public Chicken(){}//一般情况下最好保留默认的构造方法
public Chicken(int id,String name,int age){
this.id=id;
this.name=name;
this.age=age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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 print(){
System.out.println(this.toString());
}
@Override
public String toString() {
return "Chicken{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}