static关键字的使用
补充:形参的值传递机制是 基本数据类型传值,引用数据类型传地址值
1.为什么引入static?
我们创建一个又一个对象的时候,开辟多个空间,这里面会有多个属性或方法是一样的,这会照成数据的冗余,这时候引入static 让一个类的多个对象使用同一个属性或者方法,节约内存空间
2.static的使用
1.意思:静态的
2.修饰:方法、属性、代码块、内部类
3.使用static修饰属性(成员变量):静态变量/实例变量
3.1实例变量(成员变量)
1.随着创建对象而加载
3.2静态变量(成员变量)
1.随着类的加载而加载(在调用构造器的时候,构造器加载属性方法。早于对象的创建,反应到代码中就是,还没有new 对象但是可以通过类.属性的方法加载。只有写了静态的变量才能实现,故实例变不能通过类调用),但是不能通过类.用非静态属性。
总结 对象调用非静态的属性,不能调用静态的属性。静态的属性可以通过类直接调用。
2.由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中。(任何同包对象都可以调用,不同包也可通过导包调用)
3.静态变量的内存解析
public class static_text {
public static void main(String[] args) {
Chinese.nation
class Chinese{
public String name;
public int age;
public static String nation;
}
3.3 静态结构举例
System.out: System类中的静态out属性
4.使用static修饰方法(当加载类的时候就会调用类的静态方法,使用类·就是加载类)
静态方法(使用生命周期理解,先有的方法,再new方法)
1.随着类的加载而加载,所以可以通过(类.)方式进行调用,不能通过类调用非静态方法。
2.static的方法不能调用super、this,因为还没有创建对象。非static的方法可以
3.静态方法内只能调用静态方法。
4.不能被重写,没意义
非静态方法
1.需要new一个对象开辟空间才可以使用。但是在非静态方法内可以调用静态方法、静态属性和非静态方法和属性、因为非静态方法构造完成晚于静态方法、静态属性、故可以调用。但是不能通过创建对象调用静态方法
5.总结
1.在开发中,什么时候使用static属性?
1.1比如银行的利率 可以声明成static属性
1.2.开发中类的常量常常声明为static,如Math.PI。 (常量是用final修饰的不能被修改的变量)
2.在开发中,什么使用static方法?
2.1.一般操作静态属性的方法通常设置为静态的,比如根据利率计算年利息。
2.2工具类中的方法,习惯上声明为static的。比如Math、Arrays、Collections
3.创建的对象可以调用静态的方法和属性,创建的对象方法可以调用静态的方法和属性。
6.单例设计模式(学套路)以后看《大话设计模式》
6.1是什么?
是设计模式中的一种,只有一个对象,构造器是private的,外部不能造对象,调用类的某个静态方法造对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的。
6.2单例设计模式具体应用场景
网站计数器
应用程序日志
数据库连接池
读取配置文件的类
Application
windows任务管理器
windows回收站
6.1单例设计模式实现(懒汉式,饿汉式)
饿汉式实现(先new一个对象)
package text;
public class superuser {
public static void main(String[] args) {
ban a =ban.getInstance();
a.setAge(20);
}
}
package text;
public class ban {
private static int number;
private static String name;
private static int age;
private static boolean ismale;
private static ban b =new ban();//内部先造好对象,必须是static的,否则
提供的static方法不能调用,可以是public,但是不严谨就可以直接通过方法调用了,
那就不需要方法了。
private ban(){
}
public static ban getInstance() {
return b;
}
public void setAge(int age) {
ban.age = age;
}
}
懒汉式实现(啥时候用啥时候造)
package text;
public class bank {
private static int number;
private static String name;
private static int age;
private static boolean ismale;
private static bank instance =null;
private bank(){
}
public static bank getInstance(){
if (instance==null) {
instance = new bank();
return instance;
}else {
return instance;
}
}
}
6.2 区分饿汉式和懒汉式
饿汉式:
坏处:对象加载时间过长。(已经加载好对象了,生命周期长,占用空间)
好处:饿汉式式线程安全的。(以春运买票为例)
懒汉式:
好处:延迟对象的创建。(节约空间)
坏处:目前写法 线程不安全。→(到多线程的时候修改)
问:这些工具类和放到Object类使用有什么区别呢?
暂时理解,Object类还是需要创建对象来调用,只是对象们公用的方法,工具类可以不创建对象使用。
问:如果说Math 是工具类 那为什么我们直接使用Math的时候不用导包?我在不同包下使用静态类是需要导入需要类的包的
理解main方法的语法
1.main()方法作为程序入口
2.main()方法也是一个普通的静态方法
3.main()方法可以做与控制台的交互
类的成员之四:代码块
1.代码块的作用
初始化当前类、对象
2.代码块的使用
2.1 只能用static 修饰(静态代码块、非静态代码块)
1.静态代码块
随着类的加载而执行,就算不调用代码块也会自动执行。
静态代码块只执行一次
可以定义多个静态代码块
静态代码块只能调用静态的属性和方法(理解同静态方法)
静态代码块执行优先于非静态代码块
2.非静态代码块
随着方法的创建而执行,就算不调用代码块也会自动执行。
非静态代码块次数=new的对象
可以定义多个非静态代码块
可以对非静态代码块的属性赋值
非静态代码块可以调用静态和非静态的属性、方法。(理解同非静态方法)
属性可以赋值的位置总结
1.属性本身赋值
2.构造器初始化
3.方法赋值
4.对象赋值
5.代码块中赋值
3.代码块的使用场景
少用,一般用于重制属性。
4.代码块和构造器相比的执行顺序以及对于属性赋值的执行顺序
由父到子,由静到动,动构造,动构造。
默认初始化→显示初始化=静态代码块→动态代码块→构造器→方法
关键字fianl(修饰 类、方法、变量、)
1.final修饰类(不能有子类(报错))
常见的final类(String(不让继承了因为功能已经做完了)、System、)
2.final修饰方法(此方法不能被重写/报错、代码块也不行)
3.final修饰变量(此变量不能被更改/报错)
成员变量
final修饰变量当还在默认初始化的时候 ,只能初始化一次,就是说不能存在两个代码块或构造器重置,
如果在属性没有赋值,必须在构造器或代码块赋值,不能等到方法区赋值,总结为最迟必须在方法构造时赋值,不能等开始使用的时候。
可以用在属性给不同卡设置不同不可修改的卡号。(static、final)全局常量
可以考虑赋值的位置有:显示初始化,代码块中初始化、构造器初始化。
局部变量
在方法体内修饰不可更改的局部变量
在形参内修饰不可修改的形参
抽象类与抽象方法(一般用于定义方法给子类重写)
涉及内容:abstract关键字
为什么用:当一个父类诞生多个子类的时候,子类都获取了父类的方法,并且一部分子类重写的父类的方法,这时候通过父类造对象调用子类就比较麻烦,直接通过子类造子类方法,把父类变成抽象类。
引入abstract 修饰类和方法
abstract修饰类
不可以再new对象,构造器只用于子类继承父类的时候用
abstract修饰方法
抽象方法只有声明,没有方法体
包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法的。
若子类重写父类中的所有抽象方法后,此子类方法可以继承抽象父类。或子类也声明成抽象类
abstract的使用注意
不能修饰私有方法 没意义。
不能修饰静态方法,final方法,final的类,因为要重写,方法的重写不能是静态的,静态不构成重写,
抽象类一般和抽象方法同时出现
(不能重写静态方法的理解:静态方法就是写在一个类当中提供给其他类共同使用的,如果一个类中重写的那个方法,不如自己写个方法,没必要修改一个公共的方法)
静态属性可以修改,怎么深入理解静态方法不重写?
引入一个匿名类的概念,直接上代码
package Person.Test;
public abstract class Person {
int age;
String name;
Boolean ismale;
public Person(){
}
public abstract void text();
}
public class user {
public static void main(String[] args) {
Person p =new Person() {//这里是重点,new的不是Person 因为Person是抽象类,
所以这个方法是构造一个匿名类,要完成抽象方法的重写就可以构造完成。
@Override
public void text() {
System.out.println("我是匿名类");
}
};
p.text();
}
}
这样可以延申到匿名对象,匿名类的写法
模板方法涉及模式了一个模式(套路)
简单说下这个模板的思路,就是命名一个抽象类,给类一些确定的属性和变量,让其他子类重写完成方法。
package practice;
import java.lang.reflect.Method;
abstract public class Employee {
private String name ;
private int number;
private MyDate birthday;
public Employee(String name,int number,MyDate birthday){
this.name=name;
this.number=number;
this.birthday=birthday;
}
public abstract void earnings();
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", number=" + number +
", birthday=" + birthday.toString() +
'}';
}
}
package practice;
public class man extends Employee {
private static double salary;
public man(String name,int number,MyDate birthday){
super(name,number,birthday);
}
public void earnings(){
}
@Override
public String toString() {
return super.toString();
}
}
package practice;
public class MyDate{
private int years;
private int mounth;
private int date;
public MyDate(int years,int mounth,int date){
this.date=date;
this.years=years;
this.mounth=mounth;
}
@Override
public String toString() {
return "MyDate{" +
"years=" + years +
", mounth=" + mounth +
", date=" + date +
'}';
}
}
package practice;
import javax.naming.NamingEnumeration;
public class User {
public static void main(String[] args) {
man A =new man("kevin",1,new MyDate(1990,10,1));
System.out.println(A.toString());
}
}
接口(interface)
1.为什么引入接口
单个对象的继承性无法满足需求的时候,引入接口的概念,使得一个子类可以有多个父类
2.接口的使用
2.1:基本语法:implement 抽象类,interface 抽象类
2.2:interface的特点:
5.0前
1.属性默认全局常量(),方法默认公共抽象方法,没有构造器,但几乎也成父类。
5.0后
除了可以定义抽象方法外,另加可以定义静态方法,默认方法
2.子类继承父类,重写抽象方法或子类变为抽象类
3.匿名子类vs匿名实现类
匿名子类、匿名实现类、
匿名对象、非匿名对象、
(一共四种)简单写两种
第一种
public class user {
public static void main(String[] args) {
son s =new son();
s.ff(new Father() {
@Override
public void Method() {
System.out.println("匿名实现类的匿名对象");
}
});
}
}
package tttttttt;
public class son implements Father {
public void Method(){
}
public void ff(Father father){
Method();
}
}
package tttttttt;
interface Father {
void Method();
}
第二种
public class user {
public static void main(String[] args) {
Father fa =new Father() {
@Override
public void Method() {
System.out.println("匿名实现类的非匿名对象");
}
};
interface Father {
void Method();
}
4.接口实际上就是定义了一种规范
5.接口与接口之间可以继承,可以多继承。
词 匿名实现类、匿名抽象类、匿名方法 的实现
4.代理模式
总结:两个类继承一个接口,完成各自的方法,通过创建一个类的对象调用另一个类的方法,或者自己执行自己的方法,例子:我上网,我检查网线,代理服务器帮我传数据。
package NetWorkTest;
public class Net {
public static void main(String[] args) {
ProxyServer user=new ProxyServer(new Server());这里有一个知识点有意思,
把子类Server服务器 的地址值给执行的子类(因为有父类这一层关系),子类
保留了这个地址值,
在调用方法的时候,由于是Server的地址值所以调用了Server服务器的方法。
user.browse();
}
}
interface NetWork{
void browse();
}
class Server implements NetWork{
public void browse(){
System.out.println("真实的服务器访问网络");
}
}
class ProxyServer implements NetWork{
private NetWork work;
public ProxyServer(NetWork work){
this.work=work;
}
public void check(){
System.out.println("联网之前的检查工作");
}
@Override
public void browse() {
check();
work.browse();
}
}
工厂模式
创建和调用分离,
问题:为什么我创建这个类附上kevin,调用不出来。
解决:添加了两行代码见注释,解答见图
我在子类new了一个父类的对象,但是对象在别的地方开辟了空间,调不到了,开始我在子类调用本父类怎么也调不出,后面检查应该是由于我new的对象到外面开辟空间了。所以我在子类声明了一个属性接受我的地址值就解决了。
package Instance;
public class User {
public static void main(String[] args) {
Son A =new Son(new RealFather("kevin"));
System.out.println(A.getName());
}
}
package Instance;
public class Son extends RealFather implements Father{
private String name;
private RealFather realFather ;(修改内容)
public Son(RealFather realFather //我在这里new的对象,然后初始化对象属性的name,通过调用
getname怎么也调不到,主要原因是因为这是一个子父类的关系,我调用子类的get方法调不到name是因为
我调用的是继承父类的name,但实际上是我在外面开辟另一个匿名空间获得了name,我只要在子类用一个
属性接下来测试就解决问题了){
this.realFather=realFather;(修改内容)
}
public Son(){
}
@Override
public void Method() {
System.out.println("我完善了方法");
}
@Override
public String getName() {
return name;
}
}
package Instance;
public class RealFather {
private String name ="durant";
public RealFather(String name){
this.name=name;
}
public RealFather(){
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package Instance;
interface Father {
void Method();
}
空指针异常为什么(解决,小问题,写错了)
public class User {
public static void main(String[] args) {
Computer computer =new Computer();
computer.Browse(new Stencil());
computer.inter.Method();
}
}
package Agent;
public class Computer implements Interface{
Interface inter;
@Override
public void Method() {
System.out.println("检查网络是否畅通");
inter.Method();
}
public void Browse(Interface inte){
Method();
inter=inte;
}
}
package Agent;
interface Interface {
void Method();
}
Jdk8的新特性
可以定义静态方法、默认方法。使得接口更像抽象方法
1.当接口只有静态的方法或默认方法的时候继承不需要重写
2.调用接口的静态方法可以使用接口名字.方法的方式,调用接口默认方法使用new继承对象的方式,或 接口名.super.help();
public class Man implements Filial,Spoony {
public void help(){
System.out.println("我该怎么办了呢");
Filial.super.help();
}
}
3.当同时有继承父类和接口的时候,接口默认方法和父类方法同名时候调用对象的同名方法默认调用父类方法。
4.当继承接口同时有两个接口默认方法一样的时候,必须重写,否则报错
5.default不能修饰属性,当实现的两个接口有非static同名属性的时候调用会报错。
类的成员之五:内部类
什么是内部类?
一个类里面再声明一个类
内部类知识点
1.Java中允许将一个类A声明再另一个类B中,则类A就是内部类,类B称为外部类
2.内部类的分类:成员内部类vs局部内部类(方法内、代码块内、构造器内)
3.成员内部类:
作为类
1.可以用一个类中的所有权限
2.可以是abstract,interface
3.可以被权限修饰符修饰
作为一个成员内部类
1.内部类方法可以调用外部类方法,(静态调静态,非静态都可以调)
2.可以被static 修饰,正常类不行;
3.可以被protect private修饰,正常类不行;
注意方法
1.如何实例化内部类的对象
public class User {
public static void main(String[] args) {
InnerTest innerTest =new InnerTest();
InnerTest.head he =new InnerTest.head();//静态成员内部类的内部方法
he.wo();
InnerTest.ears wo =innerTest.new ears();//非静态的成员内部类的内部方法
wo.me();
}
}
2.如何在成员内部类中区分调用外部类的结构
当没有重名的时候可直接调用
当有各种重名的时候
1.外部类有属性name
2.内部类有属性name
3.外部类有方法name
4.形参 有name
package InnerClass;
public class InnerTest {
String name ;
private int age;
public void name(){
System.out.println("我是外部类的方法");
}
class ears{
String name;
public void me(String name){
System.out.println(name);//调用形参
System.out.println(this.name);//调用内部类的成员变量
System.out.println(InnerTest.this.name);//调用外部类的成员变量
InnerTest.this.name();//调用外部类的方法
}
}
内部类的使用
1.如何实例化成员内部类的对象
package Test18;
public class User {
public static void main(String[] args) {
Test test =new Test();
Test.Bird.Ability();
Test.Dog dog =test.new Dog();
Test.Bird bird =new Test.Bird();
}
}
2.如何在成员内部类中区分调用外部类结构
3.开发中局部内部类怎么用
开发中少用
比较常见的一个类中某个方法创建一个实现接口类的对象
(我吐了,怎么会有这么恶心的东西,这个类本身不想完善接口,这个类的方法想完善接口,方法本身又做不到,就在方法内部写一个类完善接口,返回)
方法一(有名对象的匿名实现类)
public Father fa() { //一个类的方法,需要返回一个接口
class aa implements Father { //一个内部类方法,完善接口
@Override
public String Method() {
return "你好";
}
}
return new aa(); //返回一个完善的接口
}
方法二、这个系统可以代写,好一点(匿名对象的匿名实现类)
public Father fa() {
return new Father() {
@Override
public String Method() {
return null;
}
};
}
复习
抽象 (给一个模板 子类继承重写)
修饰 类、方法 (抽象类,子类不一定要抽象,但一般都抽象)
不能实例化
有构造器
方法不能被static修饰,因为不能重写(静态方法不能被重写?从语义就可以看出static、final、private方法本身都是编译期绑定的(也叫前期绑定)这些方法不存在多态,他们是在还没有运行的时候,程序在编译器里面就知道该调用哪个类的哪个方法了,而其他可观察的普通方法的绑定是在运行的时候根据具体的对象决定的,因为从语义上看这些方法是可被继承的,有了多态而造成了不确定性。语法上static支持重写,但是运行效果上达不到多态目的。)、final方法、final类
接口(一个标准,一个规范)
1.多继承
2.修饰类, 属性默认是全局常量(public final),方法默认是全局抽象方法(public abstract)
3.没有构造器,不能被继承。
4.jdk8后方法可以被static(接口.方法名)、default修饰(接口.super.方法名)。
5.面向接口编程
内部类
jdk8后的版本,当方法中局部内部类的方法调用外方法的属性的时候,默认将属性变成fianl型
public void aaa(){
int a=10;
class way{
public void nn(){
a=a+1;
System.out.println(a);
}
}
最后基于目前所学知识写了一个代理模式
里面用了数组保存账号信息,用了接口写代理,还写了登陆账号密码检查,账号创建,成为vip的功能。
package FinalPractice;
public class Vpn implements USB{
public void connect(USB usb){
System.out.println("连上VPN节点");
}
public void vipconnect(USB usb){
System.out.println("连上VIP_VPN节点");
}
}
package FinalPractice;
interface USB {
void connect(USB usb);
void vipconnect(USB usb);
}
package FinalPractice;
public class Account{
private String name;
private long user;
private int password;
private long telephonenumber;
private boolean vip;
public Account(){
}
public Account(String name,Long user,int password,long telephonenumber) {
this.name = name;
this.user = user;
this.password = password;
this.telephonenumber = telephonenumber;
}
public String getName() {
return name;
}
public int getPassword() {
return password;
}
public long getTelephonenumber() {
return telephonenumber;
}
public long getUser() {
return user;
}
public boolean isvip() {
return true;
}
}
package FinalPractice;
import java.util.Scanner;
public class UI extends Account implements USB{
private Account account;
private long ac;
private long pa;
public Account acc[]=new Account[10];
Scanner scanner =new Scanner(System.in);
public void begin(){
outer:
for (;;) {
System.out.println("欢迎使用R-vpn");
System.out.println("请输入你的账号");
ac=scanner.nextLong();
System.out.println("请输入你的密码");
pa=scanner.nextLong();
for (int i = 0; i <acc.length ; i++) {
if (acc[i].getUser()==ac&& acc[i].getPassword()==pa&&acc[i].isvip()==true){
System.out.println("老板,恭喜登陆成功");
vipconnect(new Vpn());
return;
} else if (acc[i].getUser()==ac&& acc[i].getPassword()==pa){
System.out.println("恭喜你,登陆成功");
connect(new Vpn());
return;
} else {
System.out.println("请输入正确的账号或密码");
break ;
}
}
}
}
public void CreateUser(Account account){
for (int i = 0; i <acc.length ; i++) {
if (acc[i]==null){
acc[i]=account;
}
}
}
public void connect(USB usb){
System.out.println("正在检查网络连接");
usb.connect(usb);
}
public void vipconnect(USB usb){
System.out.println("正在检查网络连接");
usb.vipconnect(usb);
}
public void TobeVIP(){
for (;;) {
System.out.println("请输入你的账号");
ac=scanner.nextLong();
System.out.println("请输入你的密码");
pa=scanner.nextLong();
for (int i = 0; i <acc.length ; i++) {
if (acc[i].getUser()==ac&& acc[i].getPassword()==pa){
System.out.println("您确定要成为VIP吗,请输入yes或no");
String bcvip=scanner.next();
if (bcvip.equals("yes")) {
acc[i].isvip();
System.out.println("恭喜您,已经称为VIP了");
vipconnect(new Vpn());
return;
}else if (bcvip.equals("no")){
System.out.println("不好意思,期待您的下次光临");
return;
}else {
System.out.println("你输入的答案有误");
continue;
}
}
}
}
}
}
package FinalPractice;
public class User {
public static void main(String[] args) {
UI ui =new UI();
ui.CreateUser(new Account("kevin",17777341273l,123456,17777341273l));
ui.TobeVIP();
}