Try using it in your preferred language.

English

  • English
  • 汉语
  • Español
  • Bahasa Indonesia
  • Português
  • Русский
  • 日本語
  • 한국어
  • Deutsch
  • Français
  • Italiano
  • Türkçe
  • Tiếng Việt
  • ไทย
  • Polski
  • Nederlands
  • हिन्दी
  • Magyar
translation

Esta es una publicación traducida por IA.

제이온

Consideremos el método de fábrica estática en lugar del constructor

Seleccionar idioma

  • Español
  • English
  • 汉语
  • Bahasa Indonesia
  • Português
  • Русский
  • 日本語
  • 한국어
  • Deutsch
  • Français
  • Italiano
  • Türkçe
  • Tiếng Việt
  • ไทย
  • Polski
  • Nederlands
  • हिन्दी
  • Magyar

Texto resumido por la IA durumis

  • Los métodos de fábrica estática tienen más ventajas que los constructores, y pueden controlar efectivamente la creación de instancias de la clase.
  • JDBC es un ejemplo destacado del uso de métodos de fábrica estática, proporcionando una arquitectura flexible y escalable a través del patrón del proveedor de servicios.
  • Los métodos de fábrica estática tienen la limitación de la herencia y pueden ser difíciles de encontrar, pero se pueden utilizar de manera efectiva para un buen diseño.

Resumen

Un medio convencional para adquirir instancias de clase es usar un constructor público.


    private String nombre;
    private int edad;
    private String pasatiempo;
    private EstadoMiembro estadoMiembro;

    public Miembro(String nombre, int edad, String pasatiempo, EstadoMiembro estadoMiembro) {
        this.nombre = nombre;
        this.edad = edad;
        this.pasatiempo = pasatiempo;
        this.estadoMiembro = estadoMiembro;
    }
}
public enum EstadoMiembro {
    AVANZADO,
    INTERMEDIO,
    BÁSICO;


Aunque los constructores públicos suelen ser suficientes, a menudo es útil proporcionar métodos de fábrica estáticos para que sea más fácil para los usuarios crear instancias de la forma prevista.


Un ejemplo típico de un método de fábrica estático es el método valueOf() de Boolean.


public static Boolean valueOf(boolean b) {
    return b ? Boolean.TRUE : Boolean.FALSE;


Este método recibe un valor booleano de tipo primitivo y devuelve el objeto Boolean correspondiente.


Ventajas de los métodos de fábrica estáticos

Puede tener un nombre

Los parámetros y el constructor en sí no describen adecuadamente las características del objeto que se devolverá. Por ejemplo, es difícil entender las características de un Miembro con solo mirar el constructor principal (nombre, edad, pasatiempo, estadoMiembro) de la clase Miembro anterior.


Además, solo se puede crear un constructor con una firma, mientras que los métodos de fábrica estáticos pueden tener un nombre y se puede devolver Instancias con múltiples firmas.


    private String nombre;
    private int edad;
    private String pasatiempo;
    private EstadoMiembro estadoMiembro;

    public Miembro(String nombre, int edad, String pasatiempo, EstadoMiembro estadoMiembro) {
        this.nombre = nombre;
        this.edad = edad;
        this.pasatiempo = pasatiempo;
        this.estadoMiembro = estadoMiembro;
    }

    public static Miembro miembroBásico(String nombre, int edad, String pasatiempo) {
        return new Miembro(nombre, edad, pasatiempo, EstadoMiembro.BÁSICO);
    }

    public static Miembro miembroIntermedio(String nombre, int edad, String pasatiempo) {
        return new Miembro(nombre, edad, pasatiempo, EstadoMiembro.INTERMEDIO);
    }

    public static Miembro miembroAvanzado(String nombre, int edad, String pasatiempo) {
        return new Miembro(nombre, edad, pasatiempo, EstadoMiembro.AVANZADO);
    }


Como se muestra arriba, en lugar de usar constructores para distinguir el estado del miembro, la creación de múltiples métodos de fábrica estáticos con la misma firma permite a los usuarios crear instancias de miembro con un nivel de habilidad específico sin confusión.

Veamos las bibliotecas definidas en JDK, existe un método de fábrica estática probablePrime() en BigInteger.


public static BigInteger probablePrime(int bitLength, Random rnd) {
    if (bitLength < 2)
        throw new ArithmeticException("bitLength < 2");
    return (bitLength < SMALL_PRIME_THRESHOLD ?
            smallPrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd) :
            largePrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd));


En la comparación entre el constructor general de BigInteger y el método de fábrica estático probablePrime(), este último explicará claramente que devuelve un valor de BigInteger que es un número primo.


No es necesario crear una nueva instancia cada vez que se invoca.

public static Boolean valueOf(boolean b) {
    return (b ? Boolean.TRUE : Boolean.FALSE);


El método valueOf() de Boolean usa una caché de instancias y las devuelve. Esta característica puede mejorar significativamente el rendimiento cuando los objetos son costosos de crear a menudo, y también se puede considerar como un patrón Flyweight.


Las clases que usan un enfoque de método de fábrica estático para devolver el mismo objeto para solicitudes repetidas se denominan clases de control de instancias. Controlar instancias le permite crear instancias singulares o no instanciables. Y en tipos inmutables, se puede garantizar que haya solo una instancia.

El control de instancias es la base del patrón Flyweight, y el tipo enumerado garantiza que solo se crea una instancia.


Ejemplo

Necesita plantar árboles en Minecraft. Si crea un objeto de árbol nuevo para cada árbol, podría provocar un desbordamiento de memoria.

Por lo tanto, como arriba, los objetos de árbol rojo y verde se almacenan y solo se cambia su posición al regresar. Por supuesto, el color puede aumentar de dos a más, por lo que si guarda los árboles por color en una estructura como un mapa, será eficiente.


public class Árbol {
    // El árbol tiene los 3 siguientes
    private String color;
    private int x;
    private int y;

    // Solo crea un constructor con el color.
    public Árbol(String color) {
        this.color = color;
    }

    public void setX(int x) {
        this.x = x;
    }

    public void setY(int y) {
        this.y = y;
    }

    // Al plantar un árbol
    public void instalar(){
        System.out.println("¡Se ha instalado un árbol de "+color+" en x:"+x+" y:"+y+"!");
    }
}

public class FábricaDeÁrboles {
    // La gestión de los árboles creados se realiza con la estructura de datos HashMap.
    public static final Map mapaDeÁrboles = new HashMap<>();

    public static Árbol getÁrbol(String colorDelÁrbol){
        // Busca en el mapa si existe un árbol del color ingresado. Si existe, proporciona ese objeto.
        Árbol árbol = (Árbol)mapaDeÁrboles.get(colorDelÁrbol);

        // Si aún no existe un árbol del mismo color en el mapa, crea uno nuevo y lo proporciona.
        if(árbol == null){
            árbol = new Árbol(colorDelÁrbol);
            mapaDeÁrboles.put(colorDelÁrbol, árbol);
            System.out.println("Crear objeto nuevo");
        }
        return árbol;
    }
}

public class Principal {
    public static void main(String[] args) {
        Scanner escáner = new Scanner(System.in);

        System.out.println("Por favor, ingresa el color que deseas :)");
        for(int i=0;i<10;i++){
            // Ingresa el color del árbol
            String entrada = escáner.nextLine();
            // Obtener un árbol de la fábrica
            Árbol árbol = (Árbol)FábricaDeÁrboles.getÁrbol(entrada);
            // Configurar x,y del árbol y
            árbol.setX((int) (Math.random()*100));
            árbol.setY((int) (Math.random()*100));
            // Planta el árbol
            árbol.instalar();
        }
    }


Diferencia del patrón Singleton

El patrón Singleton solo permite crear un árbol en la clase Árbol. Por lo tanto, si usa el patrón Singleton, debe cambiar el color de la única instancia creada. Es decir, Singleton solo puede tener uno, independientemente del tipo.


Casos de uso

El patrón Flyweight se utiliza en el grupo de constantes String de Java.


Puede devolver objetos de subtipo del tipo de retorno.

Si ha utilizado el método asList() de la clase de utilidad Arrays, comprenderá esta ventaja.


public static  List asList(T... a) [
    return new ArrayList<>(a);


El método envuelve los valores en ArrayList, que es una subclase de la Lista, y los devuelve. El usuario no necesita conocer esta subclase. Es decir, tiene la flexibilidad de elegir libremente la clase del objeto de retorno, por lo que el desarrollador puede mantener la API pequeña sin exponer la implementación.


Historia de los métodos estáticos de la interfaz Java

Antes de Java 8, era imposible declarar métodos estáticos en una interfaz, por lo que si necesitaba un método estático que devolviera una interfaz llamada “Tipo”, tenía que crear una clase complementaria no instanciable llamada “Tipos” y definir el método dentro de ella.


Un ejemplo típico es que la JCF tiene 45 clases de utilidad. La mayoría de estas clases de utilidad se obtienen a través de un único método estático de fábrica en una clase complementaria llamada java.util.Collections. En particular, entre estas clases de utilidad, hay algunas que no son públicas y solo se pueden instanciar con métodos de fábrica estáticos. (Naturalmente, esta clase no se puede heredar).


Además, no expone las 45 clases, por lo que la API se vuelve mucho más pequeña.


// Ejemplo de interfaz y clase complementaria


Sin embargo, a partir de Java 8, puede agregar métodos estáticos directamente a las interfaces, por lo que ya no necesita definir clases complementarias.


Puede devolver objetos de diferentes clases según el parámetro de entrada.

Más allá de simplemente devolver subtipos, puede devolver diferentes subtipos según el valor del parámetro. Por ejemplo, si desea devolver diferentes estados de miembro según la puntuación, cree un método de fábrica estático como el siguiente y establezca la lógica de comparación en él.


public enum EstadoMiembro {

    AVANZADO(80, 100),
    INTERMEDIO(50, 79),
    BÁSICO(0, 49);

    private final int puntajeMínimo;
    private final int puntajeMáximo;

    EstadoMiembro(int puntajeMínimo, int puntajeMáximo) {
        this.puntajeMínimo = puntajeMínimo;
        this.puntajeMáximo = puntajeMáximo;
    }

    public static EstadoMiembro de(int puntaje) {
        return Arrays.stream(values())
                .filter(decideEstadoMiembro(puntaje))
                .findAny()
                .orElseThrow(() -> new NoSuchElementException("¡No existe un objeto EstadoMiembro correspondiente!"));
    }

    private static Predicate decideEstadoMiembro(int puntaje) {
        return elemento -> elemento.puntajeMínimo <= puntaje && elemento.puntajeMáximo >= puntaje;
    }
}

@DisplayName("Prueba de EstadoMiembro")
class PruebaEstadoMiembro {

    @Parametrizada
    @FuenteCsv(valor = {"0:BÁSICO", "30:BÁSICO", "50:INTERMEDIO", "70:INTERMEDIO", "80:AVANZADO", "100:AVANZADO"}, delimitador = ':')
    @DisplayName("Devuelve EstadoMiembro de forma diferente según la puntuación.")
    void de(int entrada, EstadoMiembro esperado) {
        assertThat(EstadoMiembro.de(entrada)).isEqualTo(esperado);
    }

No es necesario que la clase del objeto que se devolverá exista en el momento en que se crea el método de fábrica estático.

La frase de arriba clase del objetose refiere al archivo de clase que escribimos.

Para referencia, Class se refiere al objeto Class que se asigna al área de pila cuando el cargador de clases carga la clase. Este objeto Class contiene varios metadatos sobre la clase que escribimos.


package estructuraDeDatosDelAlgoritmo;
public abstract class TipoMétodoFábricaEstático {
    public abstract void obtenerNombre();

    public static TipoMétodoFábricaEstático obtenerNuevaInstancia() {
        TipoMétodoFábricaEstático temp = null;
        try {
            Class claseHija = Class.forName("estructuraDeDatosDelAlgoritmo.TipoMétodoFábricaEstáticoHijo"); // Reflexión
            temp = (TipoMétodoFábricaEstático) claseHija.newInstance(); // Reflexión

        } catch (ClassNotFoundException e) {
           System.out.println("¡No hay clase!");
        } catch (InstantiationException  e) {
            System.out.println("No se puede cargar en memoria.");
        } catch (IllegalAccessException  e) {
            System.out.println("¡Error al acceder al archivo de clase!");
        }

        return temp;
    }


Si observa el código anterior, puede ver que crea un objeto Class a través de la ubicación de la clase de implementación y usa la técnica de reflexión para inicializar la implementación real. En este momento, no es necesario que la clase TipoMétodoFábricaEstáticoHijo exista en el momento en que se crea el método de fábrica estático.


Sin embargo, si la implementación no está disponible en la ruta estructuraDeDatosDelAlgoritmo.TipoMétodoFábricaEstáticoHijo en el momento en que se utiliza el método de fábrica estático, se producirá un error, pero el hecho de que no haya ningún problema en el momento en que se crea el método de fábrica estático significa que es flexible.


public interface Prueba {
    int suma(int a, int b);

    // Prueba es una interfaz y no se produce ningún error incluso si no existe una clase de implementación en el momento de escribir el método de fábrica estático.
    static Prueba crear() {
        return null;
    }
}

public class Principal {
    public static void main(String[] args) {
        Prueba prueba = Prueba.crear();
        System.out.println(prueba.suma(1, 2)); // Se produce una NPE
    }


Se puede obtener la misma flexibilidad sin usar reflexión. Si observa el método create() estático en Prueba, no ocurre ningún problema en el momento de escribir incluso si no hay una implementación. Por supuesto, se produce una NPE en el momento del uso real, por lo que debe devolver la implementación más tarde.


Esta flexibilidad es la base del marco de trabajo del proveedor de servicios, y el JDBC es el representante. El proveedor en el marco de trabajo del proveedor de servicios JDBC es la implementación del servicio, y este marco controla las implementaciones y las separa del cliente (DIP).


  • Componentes del marco de trabajo del proveedor de servicios
    • Interfaz de servicio
      • Define el comportamiento de la implementación
      • Conexión de JDBC
    • API de registro de proveedores
      • El proveedor registra la implementación
      • DriverManager.registerDriver() de JDBC
    • API de acceso al servicio
      • Cuando el cliente obtiene una instancia del servicio, usa esta API. Si no especifica condiciones, devuelve la implementación predeterminada o una implementación compatible de forma cíclica.
      • Corresponde al método de fábrica estático
      • DriverManager.getConnection() de JDBC
    • (Opcional) Interfaz del proveedor de servicios
      • Si falta, la reflexión debe usarse al crear una instancia de cada implementación.
      • Controlador JDBC


El patrón de marco de trabajo del proveedor de servicios tiene varias variaciones, incluido el patrón de puente, los marcos de trabajo de inyección de dependencias, etc.


Ejemplo típico de JDBC

Class.forName("oracle.jdbc.driver.OracleDriver"); 
Connection connection = null; 
connection = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:ORA92", "root", "root"); 


Generalmente, JDBC se escribe como arriba. Usando Class.forName(), registre OracleDriver, una de las clases de implementación de Driver, y use DriverManager.getConnection() para obtener OracleDriver una de las clases de implementación de Connection.


Aquí, la Conexión es la Interfaz de Servicio, DriverManager.getConnection() es la API de Acceso al Servicio y el Driver es la Interfaz del Proveedor del Servicio. Sin embargo, DriverManager.registerDriver(), que es la API de Registro del Proveedor, no se usó. Sin embargo, podemos registrar Driver solo con Class.forName(). ¿Cómo es posible esto?


El principio de funcionamiento de Class.forName()

Este método solicita a JVM que cargue la clase si se pasa el nombre de archivo de clase físico como argumento. Entonces, el cargador de clases almacenará los metadatos de la clase en el área de método, asignará el objeto Class al área de pila. Además, cuando finaliza la carga de la clase, se inicializan los campos estáticos y el bloque estático, y en este momento se utiliza la API de registro del proveedor.


public class OracleDriver implements Driver {

    static {
        defaultDriver = null;
        Timestamp timestamp = Timestamp.valueOf("2000-01-01 00:00:00.0");
        try {
            if (defaultDriver == null) {
                defaultDriver = new OracleDriver();
                DriverManager.registerDriver(defaultDriver); // Registro de OracleDriver
            }
        } catch (RuntimeException runtimeexception) {
        } catch (SQLException sqlexception) {
        }
    }

    ...


De hecho, si observa OracleDriver, puede ver que está utilizando DriverManager.registerDriver() dentro del bloque estático para registrar OracleDriver, que es la implementación de Driver.


Análisis de la clase DriverManager

public class DriverManager {

    private DriverManager() {
    }

    private static final Map drivers = new ConcurrentHashMap();
    public static final String NOMBRE_DEL_CONTROLADOR_PREDETERMINADO = "predeterminado";

    public static void registrarControladorPredeterminado(Driver d) {
        System.out.println("Registro del controlador");
        registrarControlador(NOMBRE_DEL_CONTROLADOR_PREDETERMINADO, d);
    }

    public static void registrarControlador(String nombre, Driver d) {
        drivers.put(nombre, d);
    }

    public static Connection obtenerConexión() {
        return obtenerConexión(NOMBRE_DEL_CONTROLADOR_PREDETERMINADO);
    }

    public static Connection obtenerConexión(String nombre) {
        Driver d = drivers.get(nombre);
        if (d == null) throw new IllegalArgumentException();
        return d.getConnection();
    }


La clase DriverManager en realidad será mucho más compleja, pero si la resumes a lo esencial, se verá similar a la de arriba. Como se explicó anteriormente, al llamar a registerDriver() en el bloque estático de OracleDriver para registrar OracleDriver, y al llamar a getConnection(), el usuario puede obtener la implementación de Connection.


Al observar de cerca el método getConnection() de la API de acceso del usuario, puede ver que se obtiene Connection de la interfaz Driver. Si falta la interfaz del proveedor del servicio, Driver, la reflexión, como Class.forName(), se puede usar para devolver la implementación de Connection deseada. En este momento, no es necesario que la implementación de Connection exista en el momento en que se crea el método de fábrica estático.


En su lugar, usamos la interfaz Driver y, después de registrar dinámicamente la implementación del Driver, podemos obtener fácilmente la implementación de Connection correspondiente a este Driver.


Para referencia, analicé el código JDK real del método getConnection() de DriverManager, pero si no está particularmente interesado, puede omitirlo.


@CallerSensitive
public static Connection getConnection(String url,
    String user, String password) throws SQLException {
    java.util.Properties info = new java.util.Properties();

    if (user != null) {
        info.put("user", user);
    }
    if (password != null) {
        info.put("password", password);
    }

    return (getConnection(url, info, Reflection.getCallerClass()));


Primero, se llama al método estático público getConnection(), y se pasan url, Properties y CallerClass al método estático privado getConnection(). Aquí, Reflection.getCallerClass() tiene la función de obtener la clase que llamó a este método estático público getConnection(). Si la clase Car llamó a getConnection(), se puede obtener el objeto Class usando Reflection.getCallerClass().


private static Connection getConnection(String url, java.util.Properties info, Class caller) throws SQLException {
    ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
    synchronized(DriverManager.class) {
        if (callerCL == null) {
            callerCL = Thread.currentThread().getContextClassLoader();
        }
    }

    if(url == null) {
        throw new SQLException("La URL no puede ser nula", "08001");
    }

    SQLException reason = null;
    for(DriverInfo aDriver : registeredDrivers) {
        if(isDriverAllowed(aDriver.driver, callerCL)) {
            try {
                Connection con = aDriver.driver.connect(url, info);
                if (con != null) {
                    return (con);
                }
            } catch (SQLException ex) {
                if (reason == null) {
                    reason = ex;
                }
            }
        }
    }

    if (reason != null)    {
        throw reason;
    }
    throw new SQLException("No se encontró un controlador adecuado para "+ url, "08001");


callerCL es un objeto cargador de clases y se crea con la clase caller o el cargador de clases del hilo actual. Luego, busca aDriver uno por uno en la lista registrada de controladores registeredDrivers de la aplicación actual. Luego, si este Driver es verificado como verdadero por isDriverAllowed(), obtiene un objeto Connection con ese Driver y lo devuelve. isDriverAllowed() verifica si existe aDriver en caller.


Desventajas del método de fábrica estático

Como es necesario un constructor público o protegido para la herencia, no se puede crear una subclase si solo se proporciona un método de fábrica estático.


Sin embargo, esta restricción fomenta la composición en lugar de la herencia y, en este sentido, puede verse incluso como una ventaja de obligarte a seguir esta restricción para crear tipos inmutables.


Los métodos de fábrica estáticos son difíciles de encontrar para los programadores.

Debido a que no se indica claramente en la descripción de la API como los constructores, los desarrolladores deben escribir bien la documentación de la API y seguir las convenciones de nomenclatura ampliamente conocidas para mitigar el problema.


Convención de nomenclatura para métodos de fábrica estáticos

  • from
    • Recibe un parámetro y devuelve una instancia del tipo correspondiente.
    • Date date = Date.from(instant);
  • of
    • Recibe múltiples parámetros y devuelve una instancia del tipo apropiado.
    • Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);
  • valueOf
    • Una versión más detallada de from y of.
    • BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
  • instance 혹은 getInstance
    • Devuelve la instancia especificada como parámetro, pero no garantiza que sea la misma instancia.
    • StackWalker luke = StackWalker.getInstance(options);
  • create 혹은 newInstance
    • Lo mismo que instance o getInstance, pero garantiza que se creará y devolverá una nueva instancia.
    • Object newArray = Array.newInstance(classObject, arraylen);
  • getType
    • Lo mismo que getInstance, pero define un método de fábrica en una clase diferente de la clase que se creará.
    • FileStore fs = Files.getFileStore(path);
  • newType
    • Lo mismo que newInstance, pero define un método de fábrica en una clase diferente de la clase que se creará.
    • BufferedReader br = Files.newBufferedReader(path);
  • type
    • Una versión sucinta de getType y newType.
    • List<Complaint> litany = Collections.list(legacyLitany);


Resumen

Los métodos de fábrica estáticos y los constructores públicos tienen sus propios usos, así que utilízalos sabiamente.


Fuente

제이온
제이온
제이온
제이온
[Effective Java] Item 4. Use a private constructor to prevent instantiation Las clases de utilidad que contienen solo métodos y campos estáticos deben configurar el modificador de acceso de su constructor como privado para evitar la creación de instancias. Esto evita que los usuarios asuman que el constructor es generado automáti

28 de abril de 2024

[Effective Java] Item 2. Considere un constructor si el constructor tiene muchos parámetros Al crear objetos con muchos parámetros, el uso del patrón de constructor puede hacer que el código sea más limpio y fácil de leer. Cree un objeto de constructor con parámetros obligatorios y configure los parámetros opcionales con el método setter, luego

27 de abril de 2024

[Effective Java] Item 5. Utilice la inyección de dependencia en lugar de especificar recursos Si una clase depende de recursos externos, es mejor no usar singletons ni clases de utilidad estáticas. La inyección de dependencia puede mejorar la flexibilidad, la reutilización y la facilidad de prueba de la clase, y el uso del patrón de método de fábr

28 de abril de 2024

Modelado de datos físico El modelado de datos físico es el proceso de diseñar las tablas de una base de datos relacional para que sean realmente utilizables. Se busca optimizar el rendimiento mediante la eficiencia del espacio de almacenamiento, el particionamiento de datos, el d
제이의 블로그
제이의 블로그
제이의 블로그
제이의 블로그
제이의 블로그

9 de abril de 2024

[python] Fundamentos de Python 1: Introducción a los Módulos de Python En este artículo, se describe la migración de un programa desarrollado en PHP a Python, incluyendo los conceptos básicos de Python y el uso de módulos. Python es un lenguaje de script que admite el tipeo dinámico y es independiente de la plataforma. Ofrec
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자

27 de marzo de 2024

Modelado de datos conceptual El modelado de datos conceptual es el proceso de separar las entidades y representar la relación entre las entidades como ERD. Una entidad es una unidad de información independiente, y un atributo es la data que posee la entidad. El identificador identifi
제이의 블로그
제이의 블로그
제이의 블로그
제이의 블로그

8 de abril de 2024

Modelado de datos lógico El modelado de datos lógico es el proceso de convertir el modelado de datos conceptual en el paradigma de la base de datos relacional de acuerdo con las reglas de mapeo, manejando las relaciones 1:1, 1:N y N:M y asegurando la integridad de los datos media
제이의 블로그
제이의 블로그
제이의 블로그
제이의 블로그
제이의 블로그

9 de abril de 2024

[Examen práctico de maestro de materiales metálicos] Solución 37 Este material contiene información diversa sobre las características, métodos de prueba, tratamiento térmico, aleaciones, etc. de los materiales metálicos. Cubre diversos temas como el medidor de permeabilidad, la curva de magnetización, el examen microes
blog.naver.com/gksmftordldi
blog.naver.com/gksmftordldi
blog.naver.com/gksmftordldi
blog.naver.com/gksmftordldi
blog.naver.com/gksmftordldi

24 de abril de 2024

[Concurrencia] Operación atómica: Memory Fence y Memory Ordering Esta publicación de blog explica cómo tener en cuenta el orden de la memoria en las operaciones atómicas y la importancia de las opciones de ordenación. Se explica en detalle las diversas opciones de ordenación, como Relaxed, Acquire, Release, AcqRel y Se
곽경직
곽경직
곽경직
곽경직
곽경직

12 de abril de 2024