Java进阶05-枚举、注解

枚举和注解

枚举

  • 定义解释
    枚举是在java1.5之后加入进来的。
    枚举是列出某些有穷序列集的所有成员的程序,或者是一种特定类型对象的计数。本质就是,一个类里定义几个静态变量,每个变量都是这个类的实例。
  • 怎么使用
    简单的使用:使用关键字enum
public enum EnumFruit {

	APPLE, ORANGE, BANANA, WATERMELON
}

然后使用

public class MainEnum {

	private static String TAG = "MainEnum";

	public static <T> void println(T msg) {
		System.out.println("MainEnum===" + msg.toString());
	}

	public static void main(String[] args) {

		println(EnumFruit.APPLE.name());
		
//		EnumMap<EnumFruit, Integer> enumMap = new EnumMap<>(EnumFruit.class);
//		enumMap.put(EnumFruit.ORANGE, 56);
//		println(enumMap.get(EnumFruit.ORANGE));

	}
}

运行结果:
在这里插入图片描述
这个就是最简单的用法了。

高级一点的用法就是增加字段如:

public enum EnumFruit {
	APPLE("苹果", 10), ORANGE("橘子", 12), BANANA("香蕉", 15), WATERMELON("西瓜", 18);

	private EnumFruit(String type, int price) {
		this.type = type;
		this.price = price;
	}

	private String type;
	private int price;

	public String getType() {
		return type;

	}

	public int getPirce() {
		return price;
	}

}

给每个枚举变量都增加了描述和价格;然后增加了构造函数 和对应的获取方法。注意这里的构造函数为私有的,而且枚举变量增加了分号;结束,所以外界无法通过new来创建这个枚举对象。
测试:

public class MainEnum {

	private static String TAG = "MainEnum";

	public static <T> void println(T msg) {
		System.out.println("MainEnum===" + msg.toString());
	}

	public static void main(String[] args) {
		println(EnumFruit.APPLE.getPirce());
//		EnumMap<EnumFruit, Integer> enumMap = new EnumMap<>(EnumFruit.class);
//		enumMap.put(EnumFruit.ORANGE, 56);
//		println(enumMap.get(EnumFruit.ORANGE));
	}
}

这里我们获取苹果的价格,运行结果:
在这里插入图片描述
可以看到和我们定义的价格一样。

EnumMap的使用 这个其实和HashMap 类似。但是它是为了使用枚举 量身定做的。用法:

	public static <T> void println(T msg) {
		System.out.println("MainEnum===" + msg.toString());
	}
	public static void main(String[] args) {
//		println(EnumFruit.APPLE.getPirce());
		EnumMap<EnumFruit, Integer> enumMap = new EnumMap<>(EnumFruit.class);
		enumMap.put(EnumFruit.ORANGE, 56);
		println(enumMap.get(EnumFruit.ORANGE));
	}

而如果我们使用普通的HashMap他是不能定义key为枚举的只能如下:

	public static <T> void println(T msg) {
		System.out.println("MainEnum===" + msg.toString());
	}
	public static void main(String[] args) {
//		println(EnumFruit.APPLE.getPirce());
		
		EnumMap<EnumFruit, Integer> enumMap = new EnumMap<>(EnumFruit.class);
		enumMap.put(EnumFruit.ORANGE, 56);
		println(enumMap.get(EnumFruit.ORANGE));
		
		HashMap<String,Integer> hashMap = new HashMap<>();
		hashMap.put(EnumFruit.BANANA.getType(), 13);
		println(hashMap.get(EnumFruit.BANANA.getType()));
		
	}

EnumMap 只能接收同一枚举类型的实例作为键值且不能为null,由于枚举类型实例的数量相对固定并且有限,所以EnumMap使用数组来存放与枚举类型对应的值,毕竟数组是一段连续的内存空间,根据程序局部性原理,效率会相当高。
HashMap我们知道是数组存储数据,动态扩容。但是EnumMap 的容量其实是固定的,因为枚举数量是固定的。

枚举与switch
java 1.7后switch也对字符串进行了支持。看一下switch与枚举类型的使用:

public static void main(String[] args) {
		EnumFruit enumFruit = EnumFruit.APPLE;
		switch (enumFruit) {
		case APPLE:

			break;
		case ORANGE:

			break;
		case BANANA:

			break;
		case WATERMELON:

			break;

		default:
			break;
		}
	}

枚举与单例
单例模式网上有6-7中写法,除了 枚举方式外, 都有两个致命的缺点, 不能完全保证单例在jvm中保持唯一性.

反射创建单例对象
解决方案 : 在构造上述中判断,当多于一个实例时,再调用构造函数,直接报错.

反序列化时创建对象
解决方案 : 使用readResolve()方法来避免此事发生.

这两种缺点虽然都有方式解决,但是不免有些繁琐.

枚举类天生有这些特性.而且实现单例相当简单.

public enum EnumSingle {
	INSTANCE;
	
	public void sayHello() {
		System.out.println("Hello World");
	}
	
}

使用:

public static void main(String[] args) {
		EnumSingle.INSTANCE.sayHello();
	}

所以,枚举实现的单例,可以说是最完美和简洁的单例了.推荐大家使用这种方式创建单例.
但是,枚举类的装载和初始化时会有时间和空间的成本. 它的实现比其他方式需要更多的内存空间。而且枚举类不能再去继承其他的类,而且也不能调用构造函数传递参数。
所以在Android这种受资源约束的设备中尽量避免使用枚举单例,而选择 双重检查锁(DCL)和静态内部类的方式实现单例.

enum类中定义抽象方法
与常规抽象类一样,enum类允许我们为其定义抽象方法,然后使每个枚举实例都实现该方法,以便产生不同的行为方式:

public enum EnumFruit {
	APPLE {
		@Override
		public String getShape() {
			return "椭圆";
		}
	},
	ORANGE {
		@Override
		public String getShape() {
			return "哈哈";
		}
	},
	BANANA {
		@Override
		public String getShape() {
			return "长条";
		}
	},
	WATERMELON {
		@Override
		public String getShape() {
			return "圆形";
		}
	};

	public abstract String getShape();

}

测试:

	public static <T> void println(T msg) {
		System.out.println("MainEnum===" + msg.toString());
	}

	public static void main(String[] args) {
		println(EnumFruit.BANANA.getShape());
	}

结果:
在这里插入图片描述
其实这个东西意义不大,因为这个抽象方法并不能在外面实现。和传递

enum类与接口
由于Java单继承的原因,enum类并不能再继承其它类,但并不妨碍它实现接口,因此enum类同样是可以实现多接口的,如下就是管理不同类别:

public interface EnumFruit {
	enum Appetizer implements EnumFruit {
		SALAD, SOUP, SPRING_ROLLS;
	}

	enum MainCourse implements EnumFruit {
		LASAGNE, BURRITO, PAD_THAI, LENTILS, HUMMOUS, VINDALOO;
	}

	enum Dessert implements EnumFruit {
		TIRAMISU, GELATO, BLACK_FOREST_CAKE, FRUIT, CREME_CARAMEL;
	}

	enum Coffee implements EnumFruit {
		BLACK_COFFEE, DECAF_COFFEE, ESPRESSO, LATTE, CAPPUCCINO, TEA, HERB_TEA;
	}
}

使用:

public static void main(String[] args) {
		EnumFruit food = Appetizer.SALAD;
		EnumFruit food1 = MainCourse.LASAGNE;
		EnumFruit food2 = Dessert.GELATO;
		EnumFruit food3 = Coffee.CAPPUCCINO;
	}

枚举基本就这些用法了。

  • 优点缺点
    优点
    1 增强代码可读性
    2 去除equals两者判断 由于常量值地址唯一,使用枚举可以直接通过“==”进行两个值之间的对比,性能会有所提高。
    3 枚举更加安全-因为类型数量已经确定了,不能反射。
    4 Switch语句优势
    缺点
    1 占用内存多 比起 定义 静态常量
    2 增加学习成本

  • 原理源码
    终于到了源码解析阶段。首先看一个最简单的枚举,就是开头写的:

public enum EnumFruit {
	APPLE, ORANGE, BANANA, WATERMELON
}

我们使用xjad 反编译这个类:

package com.zh.t_enum;


public final class EnumFruit extends Enum
{

	public static final EnumFruit APPLE;
	public static final EnumFruit ORANGE;
	public static final EnumFruit BANANA;
	public static final EnumFruit WATERMELON;
	private static final EnumFruit ENUM$VALUES[];

	private EnumFruit(String s, int i)
	{
		super(s, i);
	}

	public static EnumFruit[] values()
	{
		EnumFruit aenumfruit[];
		int i;
		EnumFruit aenumfruit1[];
		System.arraycopy(aenumfruit = ENUM$VALUES, 0, aenumfruit1 = new EnumFruit[i = aenumfruit.length], 0, i);
		return aenumfruit1;
	}

	public static EnumFruit valueOf(String s)
	{
		return (EnumFruit)Enum.valueOf(com/zh/t_enum/EnumFruit, s);
	}

	static 
	{
		APPLE = new EnumFruit("APPLE", 0);
		ORANGE = new EnumFruit("ORANGE", 1);
		BANANA = new EnumFruit("BANANA", 2);
		WATERMELON = new EnumFruit("WATERMELON", 3);
		ENUM$VALUES = (new EnumFruit[] {
			APPLE, ORANGE, BANANA, WATERMELON
		});
	}
}

这下明白了吧
1 枚举类在编译的时候 就会变成一个正常的class类。
2 而且是final修饰不能被继承,同时继承了Enum抽象类。
3 我们定义的枚举变量其实是 类变量
看看Enum抽象类结构:

public abstract class Enum<E extends Enum<E>>
        implements Comparable<E>, Serializable {
    private final String name;
    public final String name() {
        return name;
    }
    private final int ordinal;
    public final int ordinal() {
        return ordinal;
    }
    protected Enum(String name, int ordinal) {
        this.name = name;
        this.ordinal = ordinal;
    }
    public String toString() {
        return name;
    }
    public final boolean equals(Object other) {
        return this==other;
    }
    public final int hashCode() {
        return super.hashCode();
    }
    protected final Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }
    public final int compareTo(E o) {
        Enum<?> other = (Enum<?>)o;
        Enum<E> self = this;
        if (self.getClass() != other.getClass() && // optimization
            self.getDeclaringClass() != other.getDeclaringClass())
            throw new ClassCastException();
        return self.ordinal - other.ordinal;
    }
    @SuppressWarnings("unchecked")
    public final Class<E> getDeclaringClass() {
        Class<?> clazz = getClass();
        Class<?> zuper = clazz.getSuperclass();
        return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
    }
    public static <T extends Enum<T>> T valueOf(Class<T> enumType,
                                                String name) {
        T result = enumType.enumConstantDirectory().get(name);
        if (result != null)
            return result;
        if (name == null)
            throw new NullPointerException("Name is null");
        throw new IllegalArgumentException(
            "No enum constant " + enumType.getCanonicalName() + "." + name);
    }

    protected final void finalize() { }
    private void readObject(ObjectInputStream in) throws IOException,
        ClassNotFoundException {
        throw new InvalidObjectException("can't deserialize enum");
    }
    private void readObjectNoData() throws ObjectStreamException {
        throw new InvalidObjectException("can't deserialize enum");
    }
}

Enum抽象类中:
1 定义了名称和顺序
2 比较大小 是通过 顺序关键字
3 禁止反序列化

  • 使用情景
    1 单例
    2 有限的集合表示
    3 看自己的取舍

  • 总结
    1.枚举并不难,编译后,它也只是个普通的final 类 继承了Enum。
    2.定义的枚举变量 就是 类变量-所以它占用的内存会高
    3.枚举单例是最好安全和简洁的。

注解

  • 定义解释
    1.5之后引入
    注解可以理解为标签,就是对某个事物的解释。标准的定义如下:
    Java 注解用于为 Java 代码提供元数据。作为元数据,注解不直接影响你的代码执行,但也有一些类型的注解实际上可以用于这一目的。

元注解
可以理解为 注解的注解,是用来描述注解的。目前一共有5中:
@Retention
Retention 的英文意为保留期的意思。当 @Retention 应用到一个注解上的时候,它解释说明了这个注解的的存活时间。

它的取值如下:

RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。
RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。

@Documented
顾名思义,这个元注解肯定是和文档有关。它的作用是能够将注解中的元素包含到 Javadoc 中去。

@Target
Target 是目标的意思,@Target 指定了注解运用的地方。

ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
ElementType.CONSTRUCTOR 可以给构造方法进行注解
ElementType.FIELD 可以给属性进行注解
ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
ElementType.METHOD 可以给方法进行注解
ElementType.PACKAGE 可以给一个包进行注解
ElementType.PARAMETER 可以给一个方法内的参数进行注解
ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举

@Inherited
Inherited 是继承的意思,但是它并不是说注解本身可以继承,而是说如果一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解。

@Repeatable
Repeatable 自然是可重复的意思。@Repeatable 是 Java 1.8 才加进来的,所以算是一个新的特性。

注解的属性
注解的属性也叫做成员变量。注解只有成员变量,没有方法。注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。

赋值的方式是在注解的括号内以 value="" 形式,多个属性之前用 ,隔开。

需要注意的是,在注解中定义属性时它的类型必须是 8 种基本数据类型外加 类、接口、注解及它们的数组。

注解中属性可以有默认值,默认值需要用 default 关键值指定。

  • 怎么使用
    注解的声明用interface 和@ 如:
@Retention(RetentionPolicy.RUNTIME)
@Target(TYPE)
public @interface Describe {
	public String type();

	public int id() default -1;

}

这里我就定义了一个注解。这个注解保留到运行期间就是 虚拟机,目标是给类 接口 枚举使用。还定义了2个属性。String 类型, int id
使用:

@Describe(type = "Hello", id = 55)
public class Apple {

	private int price;

	private String name;

	public Apple() {
	}

	public Apple(String name, int price) {
		this.price = price;
		this.name = name;
	}

	public int getPrice() {
		return price;
	}

	public void setPrice(int price) {
		this.price = price;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void call() {
		System.out.println("苹果是:" + name + ",价格是:" + price);
	}

	@Override
	public String toString() {
		return "Apple [price=" + price + ", name=" + name + "]";
	}

}

定义一个苹果类 使用了我们自定义的注解。
测试:

public static <T> void println(T msg) {
		System.out.println("MainAnnotation====" + msg.toString());
	}

	public static void main(String[] args) {
		Apple apple = new Apple("辣鸡", 78);
		apple.call();
		Describe describe = Apple.class.getAnnotation(Describe.class);
		println("describe:" + describe.getClass().getName());
		println("id:" + describe.id());
		println("type:" + describe.type());
	}

运行结果:
在这里插入图片描述
注解的使用必须要用到反射,所以需要提前掌握反射的知识。
可能会说这个还是没什么用啊。这给类的注解用处不大,但是我们可以标记给方法。可以实现 有了这个注解的方法就被调用。我们修改下:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Describe {

}

给方法使用去掉了 变量。
使用:

public class Apple {

	@Describe
	public void call() {
		System.out.println("我是苹果,价格是:10");
	}

	@Describe
	public void say() {
		System.out.println("我是香蕉,价格是:5");
	}
}

简化了Apple。call方法添加了注解。
测试:

public static void main(String[] args) {
		Apple apple = new Apple();
		// 获取Class类对象
		Class<?> appleClass = apple.getClass();
		// 获取所有的方法
		Method[] declaredMethods = appleClass.getDeclaredMethods();
		for (int i = 0; i < declaredMethods.length; i++) {
			// 获取方法
			Method method = declaredMethods[i];
			// 此方法有被Describe注解修饰
			boolean isAnnotation = method.isAnnotationPresent(Describe.class);
			if (isAnnotation) {
				try {
					// 调用方法,invoke方法有2个参数,1是调用这个方法的对象,因为方法不能自己调用自己,1是这个方法的参数
					method.invoke(appleClass.newInstance());
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					e.printStackTrace();
				} catch (InstantiationException e) {
					e.printStackTrace();
				}
			}

		}

	}

运行结果:
在这里插入图片描述
我们去掉一个注解:

public class Apple {

	@Describe
	public void call() {
		System.out.println("我是苹果,价格是:10");
	}

	public void say() {
		System.out.println("我是香蕉,价格是:5");
	}
}

再运行:
在这里插入图片描述
注解的方法就差不多了,还是比较简单的,调用的都是系统提供好的API,就是使用的时候需要用到反射 去获取注解。

  • 优点缺点
    优点:
    1 简洁
    缺点
    1 不好理解
  • 原理源码
    回到我们的注解Descriable
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Describe {

}

我们反编译一下看看:
在这里插入图片描述
看到编译后,我们定义的注解 其实就是个接口,继承了Annotation 接口
这就没了? 当然不是其实 编译器会生成一个代理类实现了整个接口,要想看到代理类需要先调用一句:
System.getProperties().put(“sun.misc.ProxyGenerator.saveGeneratedFiles”, “true”);
如:
在这里插入图片描述
它就会在根目录下生成com目录里面就有动态生成的代理类:
在这里插入图片描述
打开看看:

package com.sun.proxy;

import com.zh.annotation.Describe;
import java.lang.reflect.*;

public final class $Proxy1 extends Proxy
	implements Describe
{

	private static Method m1;
	private static Method m3;
	private static Method m2;
	private static Method m5;
	private static Method m4;
	private static Method m0;

	public $Proxy1(InvocationHandler invocationhandler)
	{
		super(invocationhandler);
	}

	public final boolean equals(Object obj)
	{
		try
		{
			return ((Boolean)super.h.invoke(this, m1, new Object[] {
				obj
			})).booleanValue();
		}
		catch (Error ) { }
		catch (Throwable throwable)
		{
			throw new UndeclaredThrowableException(throwable);
		}
	}

	public final String name()
	{
		try
		{
			return (String)super.h.invoke(this, m3, null);
		}
		catch (Error ) { }
		catch (Throwable throwable)
		{
			throw new UndeclaredThrowableException(throwable);
		}
	}

	public final String toString()
	{
		try
		{
			return (String)super.h.invoke(this, m2, null);
		}
		catch (Error ) { }
		catch (Throwable throwable)
		{
			throw new UndeclaredThrowableException(throwable);
		}
	}

	public final Class annotationType()
	{
		try
		{
			return (Class)super.h.invoke(this, m5, null);
		}
		catch (Error ) { }
		catch (Throwable throwable)
		{
			throw new UndeclaredThrowableException(throwable);
		}
	}

	public final int id()
	{
		try
		{
			return ((Integer)super.h.invoke(this, m4, null)).intValue();
		}
		catch (Error ) { }
		catch (Throwable throwable)
		{
			throw new UndeclaredThrowableException(throwable);
		}
	}

	public final int hashCode()
	{
		try
		{
			return ((Integer)super.h.invoke(this, m0, null)).intValue();
		}
		catch (Error ) { }
		catch (Throwable throwable)
		{
			throw new UndeclaredThrowableException(throwable);
		}
	}

	static 
	{
		try
		{
			m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
				Class.forName("java.lang.Object")
			});
			m3 = Class.forName("com.zh.annotation.Describe").getMethod("name", new Class[0]);
			m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
			m5 = Class.forName("com.zh.annotation.Describe").getMethod("annotationType", new Class[0]);
			m4 = Class.forName("com.zh.annotation.Describe").getMethod("id", new Class[0]);
			m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
		}
		catch (NoSuchMethodException nosuchmethodexception)
		{
			throw new NoSuchMethodError(nosuchmethodexception.getMessage());
		}
		catch (ClassNotFoundException classnotfoundexception)
		{
			throw new NoClassDefFoundError(classnotfoundexception.getMessage());
		}
	}
}

可以看到 这个代理类 继承了代理类, 实现了我们的注解接口。里面又是反射,调用了注解定义的方法。
跟踪一下 name()方法的调用流程.
构造函数需要传入
在这里插入图片描述
这就是为什么动态代理实现的时候 还是需要一个类去实现InvocationHandler接口。
在这里插入图片描述
第一个参数是动态代理的实例,第二个方法对象,第三是吃方法参数
重点看这一句
在这里插入图片描述
h是 系统自己实现的: AnnotationInvocationHandler
看下这个m3的实现:
在这里插入图片描述
负责创建代理对象AnnotationInvocationHandler, 其将变量从常量池中取出并创建map, 进而创建代理对象, 这个类就是 AnnotationParser。

我们的注解接口真在实现在哪 不得而知,后续再深入

  • 使用情景
    1 APT使用
    2 框架使用-dagger2 bufferknife rxjava 等等
    3 单元测试
    4 你想用到的地方
  • 总结
    注解本质是一个继承了Annotation的特殊接口,其具体实现类是Java运行时生成的动态代理类。通过代理对象调用自定义注解(接口)的方法,会最终调用AnnotationInvocationHandler的invoke方法。该方法会从memberValues这个Map中索引出对应的值。而memberValues的来源是Java常量池。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
4S店客户管理小程序-毕业设计,基于微信小程序+SSM+MySql开发,源码+数据库+论文答辩+毕业论文+视频演示 社会的发展和科学技术的进步,互联网技术越来越受欢迎。手机也逐渐受到广大人民群众的喜爱,也逐渐进入了每个用户的使用。手机具有便利性,速度快,效率高,成本低等优点。 因此,构建符合自己要求的操作系统是非常有意义的。 本文从管理员、用户的功能要求出发,4S店客户管理系统中的功能模块主要是实现管理员服务端;首页、个人中心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理,用户客户端:首页、车展、新闻头条、我的。门店客户端:首页、车展、新闻头条、我的经过认真细致的研究,精心准备和规划,最后测试成功,系统可以正常使用。分析功能调整与4S店客户管理系统实现的实际需求相结合,讨论了微信开发者技术与后台结合java语言和MySQL数据库开发4S店客户管理系统的使用。 关键字:4S店客户管理系统小程序 微信开发者 Java技术 MySQL数据库 软件的功能: 1、开发实现4S店客户管理系统的整个系统程序; 2、管理员服务端;首页、个人中心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理等。 3、用户客户端:首页、车展、新闻头条、我的 4、门店客户端:首页、车展、新闻头条、我的等相应操作; 5、基础数据管理:实现系统基本信息的添加、修改及删除等操作,并且根据需求进行交流信息的查看及回复相应操作。
现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本微信小程序医院挂号预约系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息,使用这种软件工具可以帮助管理人员提高事务处理效率,达到事半功倍的效果。此微信小程序医院挂号预约系统利用当下成熟完善的SSM框架,使用跨平台的可开发大型商业网站的Java语言,以及最受欢迎的RDBMS应用软件之一的MySQL数据库进行程序开发。微信小程序医院挂号预约系统有管理员,用户两个角色。管理员功能有个人中心,用户管理,医生信息管理,医院信息管理,科室信息管理,预约信息管理,预约取消管理,留言板,系统管理。微信小程序用户可以注册登录,查看医院信息,查看医生信息,查看公告资讯,在科室信息里面进行预约,也可以取消预约。微信小程序医院挂号预约系统的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。可以说该程序在帮助管理者高效率地处理工作事务的同时,也实现了数据信息的整体化,规范化与自动化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值